]> git.vomp.tv Git - jsonserver.git/blob - handler.c
Compatibility for VDR 2.1.2
[jsonserver.git] / handler.c
1 #include "handler.h"
2
3 #include <string.h>
4 #include <stdlib.h>
5 #include <sys/time.h>
6 #include <jsoncpp/json/json.h>
7 #include <string>
8
9 #include <vdr/videodir.h>
10 #include <vdr/recording.h>
11 #include <vdr/menu.h>
12 #include <vdr/timers.h>
13
14 #include "log.h"
15
16 int jsonserver_request_handler(struct mg_connection *conn)
17 {
18   Log* log = Log::getInstance();
19   const struct mg_request_info *request_info = mg_get_request_info(conn);
20   
21   if (strcmp(request_info->uri, "/jsonserver")) return 0; // not for us
22
23   char wvrequest[20];
24   int wvrl = mg_get_var(request_info->query_string, strlen(request_info->query_string), "req", wvrequest, 20);
25   if (wvrl == -1)
26   {
27     log->log("JSONServer", Log::ERR, "Could not decode req");
28     return 0;
29   }
30
31 /*
32   if (!strcmp(request_info->request_method, "OPTIONS"))
33   {
34     mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
35     mg_printf(conn, "%s", "Access-Control-Allow-Origin: *\r\n");
36     mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
37     return (void*)1;
38   }
39 */
40
41   // Get POST data
42   char postData[10000];
43   postData[0] = '\0';
44   if (!strcmp(request_info->request_method, "POST"))
45   {
46     const char* contentLength = mg_get_header(conn, "Content-Length");
47     int contentLengthI = atoi(contentLength);
48     log->log("JSONServer", Log::DEBUG, "POST data content length: %i", contentLengthI);
49     if (contentLengthI > 10000)
50     {
51       log->log("JSONServer", Log::DEBUG, "Length > 10000, rejecting");
52       return 0;
53     }
54
55     if (contentLengthI > 0)
56     {
57       // FIXME - assume for now that all post data will be small enough to have arrived immediately
58       int bytesRead = mg_read(conn, postData, contentLengthI);
59       if (bytesRead != contentLengthI)
60       {
61         log->log("JSONServer", Log::DEBUG, "Could not read up to contentLength");
62         return 0;
63       }
64       postData[contentLengthI] = '\0';
65     }
66   }
67
68   Json::Value js;
69   bool success = false;
70
71   if      (!strcmp(wvrequest, "gettime")) success = jsonserver_gettime(js);
72   else if (!strcmp(wvrequest, "diskstats")) success = jsonserver_diskstats(js);
73   else if (!strcmp(wvrequest, "reclist")) success = jsonserver_reclist(js);
74   else if (!strcmp(wvrequest, "recinfo")) success = jsonserver_recinfo(js, postData);
75   else if (!strcmp(wvrequest, "recdel")) success = jsonserver_recdel(js, postData);
76   else if (!strcmp(wvrequest, "recmove")) success = jsonserver_recmove(js, postData);
77   else if (!strcmp(wvrequest, "recrename")) success = jsonserver_recrename(js, postData);
78   else if (!strcmp(wvrequest, "recstop")) success = jsonserver_recstop(js, postData);
79   else if (!strcmp(wvrequest, "recresetresume")) success = jsonserver_recresetresume(js, postData);
80   else if (!strcmp(wvrequest, "channellist")) success = jsonserver_channellist(js);
81   else if (!strcmp(wvrequest, "channelschedule")) success = jsonserver_channelschedule(js, postData);
82   else if (!strcmp(wvrequest, "getscheduleevent")) success = jsonserver_getscheduleevent(js, postData);
83   else if (!strcmp(wvrequest, "timerlist")) success = jsonserver_timerlist(js);
84   else if (!strcmp(wvrequest, "timerdel")) success = jsonserver_timerdel(js, postData);
85   else if (!strcmp(wvrequest, "timerset")) success = jsonserver_timerset(js, postData);
86   else if (!strcmp(wvrequest, "timersetactive")) success = jsonserver_timersetactive(js, postData);
87   else if (!strcmp(wvrequest, "timerisrecording")) success = jsonserver_timerisrecording(js, postData);
88   else if (!strcmp(wvrequest, "tunersstatus")) success = jsonserver_tunersstatus(js, postData);
89   
90   if (!success) return 0; // the specific handler failed badly
91
92   // Now js will be filled
93
94   Json::StyledWriter sw;
95   std::string jsonout = sw.write(js);
96   mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
97   mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
98   mg_write(conn, jsonout.c_str(), jsonout.length());
99   return 1;
100
101   
102 /*
103   else if (event == MG_EVENT_LOG)
104   {
105     if (request_info->status_code == 400) // bad request
106     {
107       log->log("Mongoose", Log::DEBUG, "400 BAD REQUEST:");
108       log->log("Mongoose", Log::DEBUG, request_info->request_method);
109       log->log("Mongoose", Log::DEBUG, request_info->uri);
110       log->log("Mongoose", Log::DEBUG, request_info->http_version);
111       log->log("Mongoose", Log::DEBUG, request_info->query_string);
112       log->log("Mongoose", Log::DEBUG, request_info->log_message);
113       for (int i = 0; i < request_info->num_headers; i++)
114       {
115         log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
116       }
117     }
118     else
119     {
120       log->log("Mongoose", Log::DEBUG, request_info->log_message);
121       log->log("Mongoose", Log::DEBUG, request_info->uri);
122     }
123     return (void*)1;
124   }
125   
126   // other events not handled:
127   // MG_HTTP_ERROR, MG_INIT_SSL
128   // Let mongoose do something with those
129
130   return NULL;
131
132 */
133   
134 }
135
136 bool jsonserver_gettime(Json::Value& js)
137 {
138   Log* log = Log::getInstance();
139   log->log("JSONServer", Log::DEBUG, "gettime");
140
141   struct timeval tv;
142   gettimeofday(&tv, NULL);
143   
144   js["Time"] = (Json::UInt64)tv.tv_sec;
145   js["MTime"] = (Json::UInt)(tv.tv_usec/1000);
146   js["Result"] = true;
147   return true;
148 }
149
150 bool jsonserver_diskstats(Json::Value& js)
151 {
152   Log* log = Log::getInstance();
153   log->log("JSONServer", Log::DEBUG, "diskstats");
154   
155   int FreeMB;
156   int UsedMB;
157
158 #if APIVERSNUM > 20101
159   int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB, &UsedMB);
160 #else
161   int Percent = VideoDiskSpace(&FreeMB, &UsedMB);
162 #endif
163   
164   js["FreeMiB"] = FreeMB;
165   js["UsedMiB"] = UsedMB;
166   js["Percent"] = Percent;
167   
168   js["Result"] = true;
169   return true;
170 }
171
172 bool jsonserver_reclist(Json::Value& js)
173 {
174   Log* log = Log::getInstance();
175   log->log("JSONServer", Log::DEBUG, "reclist");
176
177   Json::Value jsrecordings(Json::arrayValue);
178   cRecordings Recordings;
179   Recordings.Load();
180   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
181   {
182     Json::Value oneRec;
183     oneRec["StartTime"] = (Json::UInt)recording->Start();
184     oneRec["Length"] = (Json::UInt)recording->LengthInSeconds();
185     oneRec["IsNew"] = recording->IsNew();
186     oneRec["Name"] = recording->Name();
187     oneRec["Filename"] = recording->FileName();
188     oneRec["FileSizeMB"] = recording->FileSizeMB();
189
190     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
191     if (rc) oneRec["CurrentlyRecording"] = true;
192     else    oneRec["CurrentlyRecording"] = false;
193     
194     jsrecordings.append(oneRec);
195   }
196   js["Recordings"] = jsrecordings;
197   
198   return true;
199 }
200
201 bool jsonserver_recinfo(Json::Value& js, const char* postData)
202 {
203   Log* log = Log::getInstance();
204   log->log("JSONServer", Log::DEBUG, "recinfo");
205
206   char reqfilename[1000];
207   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
208   if (mgv1 == -1)
209   {
210     log->log("JSONServer", Log::ERR, "Could not decode filename");
211     js["Result"] = false;
212     js["Error"] = "Could not decode filename";
213     return true;
214   }
215
216   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
217
218   cRecordings Recordings;
219   Recordings.Load(); // probably have to do this
220   cRecording *recording = Recordings.GetByName(reqfilename);
221
222   if (!recording)
223   {
224     log->log("JSONServer", Log::ERR, "recinfo found no recording");
225     js["Result"] = false;
226     return true;
227   }
228
229   js["IsNew"] = recording->IsNew();
230   js["LengthInSeconds"] = recording->LengthInSeconds();
231   js["FileSizeMB"] = recording->FileSizeMB();
232   js["Name"] = recording->Name() ? recording->Name() : Json::Value::null;
233   js["Priority"] = recording->Priority();
234   js["LifeTime"] = recording->Lifetime();
235   js["Start"] = (Json::UInt)recording->Start();
236
237   js["CurrentlyRecordingStart"] = 0;
238   js["CurrentlyRecordingStop"] = 0;
239   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
240   if (rc)
241   {
242     js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
243     js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
244   }
245
246   js["ResumePoint"] = 0;
247
248   const cRecordingInfo *info = recording->Info();
249   if (info)
250   {
251     js["ChannelName"] = info->ChannelName() ? info->ChannelName() : Json::Value::null;
252     js["Title"] = info->Title() ? info->Title() : Json::Value::null;
253     js["ShortText"] = info->ShortText() ? info->ShortText() : Json::Value::null;
254     js["Description"] = info->Description() ? info->Description() : Json::Value::null;
255
256     const cComponents* components = info->Components();
257     if (!components)
258     {
259       js["Components"] = Json::Value::null;
260     }
261     else
262     {
263       Json::Value jscomponents;
264
265       tComponent* component;
266       for (int i = 0; i < components->NumComponents(); i++)
267       {
268         component = components->Component(i);
269
270         Json::Value oneComponent;
271         oneComponent["Stream"] = component->stream;
272         oneComponent["Type"] = component->type;
273         oneComponent["Language"] = component->language ? component->language : Json::Value::null;
274         oneComponent["Description"] = component->description ? component->description : Json::Value::null;
275         jscomponents.append(oneComponent);
276       }
277
278       js["Components"] = jscomponents;
279     }
280
281     cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
282     if (ResumeFile.Read() >= 0) js["ResumePoint"] = floor(ResumeFile.Read() / info->FramesPerSecond());
283   }
284
285   js["Result"] = true;
286   return true;
287 }
288
289 bool jsonserver_recstop(Json::Value& js, const char* postData)
290 {
291   Log* log = Log::getInstance();
292   log->log("JSONServer", Log::DEBUG, "recstop");
293   
294   char reqfilename[1000];
295   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
296   if (mgv1 == -1)
297   {
298     log->log("JSONServer", Log::ERR, "Could not decode filename");
299     js["Result"] = false;
300     js["Error"] = "Could not decode filename";
301     return true;
302   }
303   
304   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
305   
306   cRecordings Recordings;
307   Recordings.Load(); // probably have to do this
308   cRecording *recording = Recordings.GetByName(reqfilename);
309   
310   if (!recording)
311   {
312     log->log("JSONServer", Log::ERR, "recstop found no recording");
313     js["Result"] = false;
314     return true;
315   }
316
317   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
318   if (!rc)
319   {
320     log->log("JSONServer", Log::ERR, "recstop - not currently recording");
321     js["Result"] = false;
322     return true;
323   }
324
325   if (Timers.BeingEdited())
326   {
327     log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
328     js["Result"] = false;
329     return true;
330   }
331
332   cTimer* timer = rc->Timer();
333   if (!timer)
334   {
335     log->log("JSONServer", Log::ERR, "recstop - timer not found");
336     js["Result"] = false;
337     return true;
338   }
339   
340   timer->ClrFlags(tfActive);
341   Timers.SetModified();
342   
343   js["Result"] = true;
344   return true;
345 }  
346   
347 bool jsonserver_recdel(Json::Value& js, const char* postData)
348 {
349   Log* log = Log::getInstance();
350   log->log("JSONServer", Log::DEBUG, "recdel");
351
352   char reqfilename[1000];
353   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
354   if (mgv1 == -1)
355   {
356     log->log("JSONServer", Log::ERR, "Could not decode filename");
357     js["Result"] = false;
358     js["Error"] = "Could not decode filename";
359     return true;
360   }
361
362   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
363   
364   cRecordings Recordings;
365   Recordings.Load(); // probably have to do this
366   cRecording *recording = Recordings.GetByName(reqfilename);
367
368   if (!recording)
369   {
370     js["Result"] = false;
371     js["Error"] = "Could not find recording to delete";
372     return true;
373   }
374
375   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
376   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
377   if (rc)
378   {
379     js["Result"] = false;
380     js["Error"] = "This recording is still recording.. ho ho";
381     return true;
382   }
383
384   if (recording->Delete())
385   {
386     ::Recordings.DelByName(recording->FileName());
387     js["Result"] = true;
388   }
389   else
390   {
391     js["Result"] = false;
392     js["Error"] = "Failed to delete recording";
393   }
394
395   return true;
396 }
397
398 bool jsonserver_recmove(Json::Value& js, const char* postData)
399 {
400   Log* log = Log::getInstance();
401   log->log("JSONServer", Log::DEBUG, "recmove");
402
403   char* fileNameToMove = NULL;
404   char* requestedNewPath = NULL;
405   char* dateDirName = NULL;
406   char* titleDirName = NULL;
407   char* folderName = NULL;
408   char* newContainer = NULL;
409   char* newDir = NULL;
410   
411   try
412   {
413     int postDataLen = strlen(postData)+1;
414     fileNameToMove = new char[postDataLen];
415     int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToMove, postDataLen);
416     requestedNewPath = new char[postDataLen];
417     int mgv2 = mg_get_var(postData, postDataLen-1, "newpath", requestedNewPath, postDataLen);
418
419     if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToMove) || !strlen(requestedNewPath))
420     {
421       log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
422       throw 1;
423     }
424
425     cRecordings Recordings;
426     Recordings.Load(); // probably have to do this
427     cRecording* recordingObj = Recordings.GetByName(fileNameToMove);
428     if (!recordingObj) throw 2;
429     
430     cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
431     if (rc) throw 3;
432
433     log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->Name());
434     log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->FileName());
435     log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewPath);
436
437     const char* t = recordingObj->FileName();
438
439     int k, j, m;
440
441     // Find the datedirname
442     for(k = strlen(t) - 1; k >= 0; k--)
443     {
444       if (t[k] == '/')
445       {
446         log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
447         dateDirName = new char[strlen(&t[k+1]) + 1];
448         strcpy(dateDirName, &t[k+1]);
449         break;
450       }
451     }
452
453     // Find the titledirname
454
455     for(j = k-1; j >= 0; j--)
456     {
457       if (t[j] == '/')
458       {
459         log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
460         titleDirName = new char[k - j];
461         memcpy(titleDirName, &t[j+1], k - j - 1);
462         titleDirName[k - j - 1] = '\0';
463         break;
464       }
465     }
466
467     // Find the foldername
468
469 #if APIVERSNUM > 20101
470     const char* vidDirStr = cVideoDirectory::Name();
471 #else
472     const char* vidDirStr = VideoDirectory;
473 #endif
474     int vidDirStrLen = strlen(vidDirStr);
475
476     log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, vidDirStrLen);
477     if (j > vidDirStrLen) // Rec is in a subfolder now
478     {
479       for(m = j-1; m >= 0; m--)
480       {
481         if (t[m] == '/')
482         {
483           log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
484           folderName = new char[j - m];
485           memcpy(folderName, &t[m+1], j - m - 1);
486           folderName[j - m - 1] = '\0';
487           break;
488         }
489       }
490     }
491
492     ExchangeChars(requestedNewPath, true);
493
494     log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
495     log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
496     log->log("JSONServer", Log::DEBUG, "viddir: %s", vidDirStr);
497     if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
498     log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewPath);
499
500     // Could be a new path - construct that first and test
501     newContainer = new char[vidDirStrLen + strlen(requestedNewPath) + strlen(titleDirName) + 1];
502     sprintf(newContainer, "%s%s", vidDirStr, requestedNewPath);
503     log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
504     struct stat dstat;
505     int statret = stat(newContainer, &dstat);
506     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
507     {
508       log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
509       int mkdirret = mkdir(newContainer, 0755);
510       if (mkdirret != 0) throw 4;
511     }
512     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
513     {
514       // Something exists but it's not a dir
515       throw 5;
516     }
517
518     // New path now created or was there already
519
520     sprintf(newContainer, "%s%s%s", vidDirStr, requestedNewPath, titleDirName);
521     log->log("JSONServer", Log::DEBUG, "%s", newContainer);
522
523     statret = stat(newContainer, &dstat);
524     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
525     {
526       log->log("JSONServer", Log::DEBUG, "new dir does not exist (2)");
527       int mkdirret = mkdir(newContainer, 0755);
528       if (mkdirret != 0) throw 6;
529     }
530     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
531     {
532       // Something exists but it's not a dir
533       throw 7;
534     }
535
536     // Ok, the directory container has been made, or it pre-existed.
537
538     newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
539     sprintf(newDir, "%s/%s", newContainer, dateDirName);
540
541     log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
542     if (rename(t, newDir) != 0) throw 8;
543     
544     // Success. Test for remove old dir containter
545     char* tempOldTitleDir = new char[k+1];
546     memcpy(tempOldTitleDir, t, k);
547     tempOldTitleDir[k] = '\0';
548     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
549     rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
550     delete[] tempOldTitleDir;
551
552     // Test for remove old foldername
553     if (folderName)
554     {
555       char* tempOldFolderName = new char[j+1];
556       memcpy(tempOldFolderName, t, j);
557       tempOldFolderName[j] = '\0';
558       log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldfoldername: %s", j+1, j, strlen(tempOldFolderName), tempOldFolderName);
559       /*
560       DESCRIPTION
561       rmdir() deletes a directory, which must be empty.
562       ENOTEMPTY - pathname  contains  entries  other than . and ..
563       So, should be safe to call rmdir on non-empty dir
564       */
565       rmdir(tempOldFolderName); // can't do anything about a fail result at this point.
566       delete[] tempOldFolderName;
567     }
568
569     ::Recordings.Update();
570     js["Result"] = true;
571     js["NewRecordingFileName"] = newDir;
572   }
573   catch (int e)
574   {
575     js["Result"] = false;
576     if (e == 1)
577     {
578       log->log("JSONServer", Log::ERR, "Bad parameters");
579       js["Error"] = "Bad request parameters";
580     }
581     else if (e == 2)
582     {
583       log->log("JSONServer", Log::ERR, "Could not find recording to move");
584       js["Error"] = "Bad filename";
585     }
586     else if (e == 3)
587     {
588       log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
589       js["Error"] = "Cannot move recording in progress";
590     }
591     else if (e == 4)
592     {
593       log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
594       js["Error"] = "Failed to create new directory (1)";
595     }
596     else if (e == 5)
597     {
598       log->log("JSONServer", Log::ERR, "Something already exists? (1)");
599       js["Error"] = "Something already exists at the new path (1)";
600     }
601     else if (e == 6)
602     {
603       log->log("JSONServer", Log::ERR, "Failed to make new dir (2)");
604       js["Error"] = "Failed to create new directory (2)";
605     }
606     else if (e == 7)
607     {
608       log->log("JSONServer", Log::ERR, "Something already exists?");
609       js["Error"] = "Something already exists at the new path";
610     }
611     else if (e == 8)
612     {
613       log->log("JSONServer", Log::ERR, "Rename failed");
614       js["Error"] = "Move failed";
615     }
616   }
617
618   if (fileNameToMove)   delete[] fileNameToMove;
619   if (requestedNewPath) delete[] requestedNewPath;
620   if (dateDirName)      delete[] dateDirName;
621   if (titleDirName)     delete[] titleDirName;
622   if (folderName)       delete[] folderName;
623   if (newContainer)     delete[] newContainer;
624   if (newDir)           delete[] newDir;
625
626   return true;
627 }
628
629 bool jsonserver_recrename(Json::Value& js, const char* postData)
630 {
631   Log* log = Log::getInstance();
632   log->log("JSONServer", Log::DEBUG, "recrename");
633   
634   char* fileNameToRename = NULL;
635   char* requestedNewName = NULL;
636   char* dateDirName = NULL;
637   char* titleDirName = NULL;
638   char* folderName = NULL;
639   char* newContainer = NULL;
640   char* newDir = NULL;
641   
642   try
643   {
644     int postDataLen = strlen(postData)+1;
645     fileNameToRename = new char[postDataLen];
646     int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToRename, postDataLen);
647     requestedNewName = new char[postDataLen];
648     int mgv2 = mg_get_var(postData, postDataLen-1, "newname", requestedNewName, postDataLen);
649     
650     if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToRename) || !strlen(requestedNewName))
651     {
652       log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
653       throw 1;
654     }
655     
656     cRecordings Recordings;
657     Recordings.Load(); // probably have to do this
658     cRecording* recordingObj = Recordings.GetByName(fileNameToRename);
659     if (!recordingObj) throw 2;
660     
661     cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
662     if (rc) throw 3;
663     
664     log->log("JSONServer", Log::DEBUG, "renaming recording: %s", recordingObj->Name());
665     log->log("JSONServer", Log::DEBUG, "renaming recording: %s", recordingObj->FileName());
666     log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewName);
667     
668     const char* t = recordingObj->FileName();
669     
670     int k, j, m;
671     
672     // Find the datedirname
673     for(k = strlen(t) - 1; k >= 0; k--)
674     {
675       if (t[k] == '/')
676       {
677         log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
678         dateDirName = new char[strlen(&t[k+1]) + 1];
679         strcpy(dateDirName, &t[k+1]);
680         break;
681       }
682     }
683     
684     // Find the titledirname
685     
686     for(j = k-1; j >= 0; j--)
687     {
688       if (t[j] == '/')
689       {
690         log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
691         titleDirName = new char[k - j];
692         memcpy(titleDirName, &t[j+1], k - j - 1);
693         titleDirName[k - j - 1] = '\0';
694         break;
695       }
696     }
697     
698     // Find the foldername
699
700 #if APIVERSNUM > 20101
701     const char* vidDirStr = cVideoDirectory::Name();
702 #else
703     const char* vidDirStr = VideoDirectory;
704 #endif
705     int vidDirStrLen = strlen(vidDirStr);
706
707     log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, vidDirStrLen);
708     if (j > vidDirStrLen) // Rec is in a subfolder now
709     {
710       for(m = j-1; m >= 0; m--)
711       {
712         if (t[m] == '/')
713         {
714           log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
715           folderName = new char[j - m];
716           memcpy(folderName, &t[m+1], j - m - 1);
717           folderName[j - m - 1] = '\0';
718           break;
719         }
720       }
721     }
722     
723     ExchangeChars(requestedNewName, true);
724     
725     log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
726     log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
727     log->log("JSONServer", Log::DEBUG, "viddir: %s", vidDirStr);
728     if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
729     log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewName);
730    
731     // Could be a new path - construct that first and test
732
733     if (folderName)
734     {
735       newContainer = new char[vidDirStrLen + 1 + strlen(folderName) + 1 + strlen(requestedNewName) + 1];
736       sprintf(newContainer, "%s/%s/%s", vidDirStr, folderName, requestedNewName);
737     }
738     else
739     {
740       newContainer = new char[vidDirStrLen + 1 + strlen(requestedNewName) + 1];
741       sprintf(newContainer, "%s/%s", vidDirStr, requestedNewName);
742     }
743     log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
744     struct stat dstat;
745     int statret = stat(newContainer, &dstat);
746     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
747     {
748       log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
749       int mkdirret = mkdir(newContainer, 0755);
750       if (mkdirret != 0) throw 4;
751     }
752     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
753     {
754       // Something exists but it's not a dir
755       throw 5;
756     }
757     
758     // New path now created or was there already
759     
760     newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
761     sprintf(newDir, "%s/%s", newContainer, dateDirName);
762     
763     log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
764     if (rename(t, newDir) != 0) throw 8;
765     
766     // Success. Test for remove old dir containter
767     char* tempOldTitleDir = new char[k+1];
768     memcpy(tempOldTitleDir, t, k);
769     tempOldTitleDir[k] = '\0';
770     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
771     rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
772     delete[] tempOldTitleDir;
773     
774     ::Recordings.Update();
775     js["Result"] = true;
776     js["NewRecordingFileName"] = newDir;
777   }
778   catch (int e)
779   {
780     js["Result"] = false;
781     if (e == 1)
782     {
783       log->log("JSONServer", Log::ERR, "Bad parameters");
784       js["Error"] = "Bad request parameters";
785     }
786     else if (e == 2)
787     {
788       log->log("JSONServer", Log::ERR, "Could not find recording to move");
789       js["Error"] = "Bad filename";
790     }
791     else if (e == 3)
792     {
793       log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
794       js["Error"] = "Cannot move recording in progress";
795     }
796     else if (e == 4)
797     {
798       log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
799       js["Error"] = "Failed to create new directory (1)";
800     }
801     else if (e == 5)
802     {
803       log->log("JSONServer", Log::ERR, "Something already exists? (1)");
804       js["Error"] = "Something already exists at the new path (1)";
805     }
806     else if (e == 8)
807     {
808       log->log("JSONServer", Log::ERR, "Rename failed");
809       js["Error"] = "Move failed";
810     }
811   }
812   
813   if (fileNameToRename) delete[] fileNameToRename;
814   if (requestedNewName) delete[] requestedNewName;
815   if (dateDirName)      delete[] dateDirName;
816   if (titleDirName)     delete[] titleDirName;
817   if (folderName)       delete[] folderName;
818   if (newContainer)     delete[] newContainer;
819   if (newDir)           delete[] newDir;
820   
821   return true;
822 }
823
824 bool jsonserver_recresetresume(Json::Value& js, const char* postData)
825 {
826   Log* log = Log::getInstance();
827   log->log("JSONServer", Log::DEBUG, "recresetresume");
828
829   char reqfilename[1000];
830   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
831   if (mgv1 == -1)
832   {
833     log->log("JSONServer", Log::ERR, "Could not decode filename");
834     js["Result"] = false;
835     js["Error"] = "Could not decode filename";
836     return true;
837   }
838
839   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
840
841   cRecordings Recordings;
842   Recordings.Load(); // probably have to do this
843   cRecording *recording = Recordings.GetByName(reqfilename);
844
845   if (!recording)
846   {
847     js["Result"] = false;
848     js["Error"] = "Could not find recording to reset resume";
849     return true;
850   }
851
852   log->log("JSONServer", Log::DEBUG, "Reset resume for: %s", recording->Name());
853
854   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
855   if (ResumeFile.Read() >= 0)
856   {
857     ResumeFile.Delete();
858     js["Result"] = true;
859     return true;
860   }
861   else
862   {
863     js["Result"] = false;
864     js["Error"] = "Recording has no resume point";
865     return true;
866   }
867 }
868
869 bool jsonserver_channellist(Json::Value& js)
870 {
871   Log* log = Log::getInstance();
872   log->log("JSONServer", Log::DEBUG, "channellist");
873
874   Json::Value jschannels(Json::arrayValue);
875   
876 //  int type;
877   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
878   {
879     if (!channel->GroupSep())
880     {
881 //      log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
882
883 //      if (channel->Vpid()) type = 1;
884 //      else if (channel->Apid(0)) type = 2;
885 //      else continue;
886
887       Json::Value oneChannel;
888       oneChannel["Number"] = channel->Number();
889 //      oneChannel["Type"] = type;
890       oneChannel["Name"] = channel->Name();
891 //#if VDRVERSNUM < 10703
892 //      oneChannel["VType"] = 2;
893 //#else
894 //      oneChannel["VType"] = channel->Vtype();
895 //#endif
896       jschannels.append(oneChannel);    
897     }
898   }
899   js["Channels"] = jschannels;
900   
901   return true;
902 }
903
904 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
905 {
906   Log* log = Log::getInstance();
907   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
908
909   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);  
910   char sStartTime[15];      int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);  
911   char sDuration[15];       int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);  
912
913   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
914   {
915     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
916     js["Result"] = false;
917     js["Error"] = "Bad request parameters";
918     return true;
919   }
920
921   int channelNumber = atoi(sChannelNumber);
922   int startTime = atoi(sStartTime); 
923   int duration = atoi(sDuration); 
924
925   cChannel* channel = NULL;
926   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
927   {
928     if (channel->GroupSep()) continue;
929     if (channel->Number() == channelNumber) break;
930   }
931
932   if (!channel)
933   {
934     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
935     js["Result"] = false;
936     js["Error"] = "Could not find channel";
937     return true;
938   }
939
940   cSchedulesLock MutexLock;
941   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
942   if (!Schedules)
943   {
944     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
945     js["Result"] = false;
946     js["Error"] = "Internal schedules error (1)";
947     return true;
948   }
949   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
950   if (!Schedule)     
951   {
952     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
953     js["Result"] = false;
954     js["Error"] = "Internal schedules error (2)";
955     return true;
956   }
957     
958   Json::Value jsevents(Json::arrayValue);
959
960   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
961   {
962     //in the past filter
963     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
964    //start time filter
965     if ((event->StartTime() + event->Duration()) <= startTime) continue;
966     //duration filter
967     if (event->StartTime() >= (startTime + duration)) continue;
968
969     Json::Value oneEvent;
970     oneEvent["ID"] = event->EventID();
971     oneEvent["Time"] = (Json::UInt)event->StartTime();
972     oneEvent["Duration"] = event->Duration();
973     oneEvent["Title"] = event->Title() ? event->Title() : "";
974     oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
975     oneEvent["HasTimer"] = event->HasTimer();
976     //oneEvent["Description"] = event->Description() ? event->Description() : "";
977     jsevents.append(oneEvent);
978   }
979
980   js["Result"] = true;
981   js["Events"] = jsevents;
982   return true;
983 }
984
985 bool jsonserver_getscheduleevent(Json::Value& js, const char* postData)
986 {
987   Log* log = Log::getInstance();
988   log->log("JSONServer", Log::DEBUG, "getscheduleevent '%s'", postData);
989   
990   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);
991   char sEventID[15];        int mgv2 = mg_get_var(postData, strlen(postData), "eventid", sEventID, 15);
992   
993   if ( (mgv1 == -1) || (mgv2 == -1) )
994   {
995     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
996     js["Result"] = false;
997     js["Error"] = "Bad request parameters";
998     return true;
999   }
1000
1001   int channelNumber = atoi(sChannelNumber);
1002   int eventID = atoi(sEventID);
1003   
1004   const cEvent* event = jsonserver_getEvent(js, channelNumber, eventID, 0);
1005   if (!event)
1006   {
1007     js["Result"] = false;
1008     return true;
1009   }
1010   
1011   Json::Value oneEvent;
1012   oneEvent["ID"] = event->EventID();
1013   oneEvent["Time"] = (Json::UInt)event->StartTime();
1014   oneEvent["Duration"] = event->Duration();
1015   oneEvent["Title"] = event->Title() ? event->Title() : "";
1016   oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
1017   oneEvent["Description"] = event->Description() ? event->Description() : "";
1018   oneEvent["HasTimer"] = event->HasTimer();
1019   oneEvent["RunningStatus"] = event->RunningStatus();
1020
1021   js["Result"] = true;
1022   js["Event"] = oneEvent;
1023   return true;
1024 }
1025
1026 const cEvent* jsonserver_getEvent(Json::Value& js, int channelNumber, int eventID, int aroundTime)
1027 {
1028   Log* log = Log::getInstance();
1029   
1030   cChannel* channel = NULL;
1031   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
1032   {
1033     if (channel->GroupSep()) continue;
1034     if (channel->Number() == channelNumber) break;
1035   }
1036
1037   if (!channel)
1038   {
1039     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
1040     js["Error"] = "Could not find channel";
1041     return NULL;
1042   }
1043
1044   cSchedulesLock MutexLock;
1045   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1046   if (!Schedules)
1047   {
1048     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
1049     js["Error"] = "Internal schedules error (1)";
1050     return NULL;
1051   }
1052   
1053   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1054   if (!Schedule)
1055   {
1056     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
1057     js["Error"] = "Internal schedules error (2)";
1058     return NULL;
1059   }
1060   
1061   const cEvent* event = NULL;
1062   if (eventID)
1063   {
1064     event = Schedule->GetEvent(eventID);
1065   }
1066   else
1067   {
1068     event = Schedule->GetEventAround(aroundTime);
1069   }
1070   
1071   if (!event)
1072   {
1073     log->log("JSONServer", Log::ERR, "Could not find requested event: %i", eventID);
1074     js["Error"] = "Internal schedules error (3)";
1075     return NULL;
1076   }
1077
1078   return event;
1079 }
1080
1081 bool jsonserver_timerlist(Json::Value& js)
1082 {
1083   Log* log = Log::getInstance();
1084   log->log("JSONServer", Log::DEBUG, "timerlist");
1085
1086   Json::Value jstimers(Json::arrayValue);
1087   
1088   cTimer *timer;
1089   int numTimers = Timers.Count();
1090
1091   for (int i = 0; i < numTimers; i++)
1092   {
1093     timer = Timers.Get(i);
1094     Json::Value oneTimer;
1095     oneTimer["Active"] = timer->HasFlags(tfActive);
1096     oneTimer["Recording"] = timer->Recording();
1097     oneTimer["Pending"] = timer->Pending();
1098     oneTimer["Priority"] = timer->Priority();
1099     oneTimer["Lifetime"] = timer->Lifetime();
1100     oneTimer["ChannelNumber"] = timer->Channel()->Number();
1101     oneTimer["ChannelID"] = (const char *)timer->Channel()->GetChannelID().ToString();
1102     oneTimer["StartTime"] = (int)timer->StartTime();
1103     oneTimer["StopTime"] = (int)timer->StopTime();
1104     oneTimer["Day"] = (int)timer->Day();
1105     oneTimer["WeekDays"] = timer->WeekDays();
1106     oneTimer["Name"] = timer->File();
1107     
1108     const cEvent* event = timer->Event();
1109     if (event)
1110     {
1111       oneTimer["EventID"] = event->EventID();
1112     }
1113     else
1114     {
1115       int channelNumber = timer->Channel()->Number();
1116       int aroundTime = timer->StartTime() + 1;
1117       log->log("JSONServer", Log::DEBUG, "%i", aroundTime);
1118
1119       const cEvent* eventAround = jsonserver_getEvent(js, channelNumber, 0, aroundTime);
1120       if (eventAround)
1121       {
1122         oneTimer["EventID"] = eventAround->EventID();
1123       }
1124       else
1125       {
1126         oneTimer["EventID"] = 0;
1127       }
1128     }
1129
1130     jstimers.append(oneTimer);
1131   }
1132   
1133   js["Timers"] = jstimers;
1134   js["Result"] = true;
1135   return true;
1136 }
1137
1138 bool jsonserver_timerset(Json::Value& js, const char* postData)
1139 {
1140   Log* log = Log::getInstance();
1141   log->log("JSONServer", Log::DEBUG, "timerset");
1142
1143   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
1144
1145   if (mgv1 == -1)
1146   {
1147     log->log("JSONServer", Log::ERR, "Could not get timerstring");
1148     js["Result"] = false;
1149     js["Error"] = "Bad request parameters";
1150     return true;
1151   }
1152
1153   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
1154   cTimer *timer = new cTimer;
1155   if (!timer->Parse(sTimerString))
1156   {
1157     delete timer;
1158     js["Result"] = false;
1159     js["Error"] = "Failed to parse timer request details";
1160     return true;
1161   }
1162
1163   cTimer *t = Timers.GetTimer(timer);
1164   if (t)
1165   {
1166     delete timer;
1167     js["Result"] = false;
1168     js["Error"] = "Timer already exists";
1169     return true;
1170   }
1171
1172   Timers.Add(timer);
1173   Timers.SetModified();
1174   js["Result"] = true;
1175   return true;
1176 }
1177
1178 bool jsonserver_timersetactive(Json::Value& js, const char* postData)
1179 {
1180   Log* log = Log::getInstance();
1181   log->log("JSONServer", Log::DEBUG, "timersetactive");
1182
1183   char rChannelID[50];  int mgv1 = mg_get_var(postData, strlen(postData), "ChannelID", rChannelID, 50);
1184   char rName[1024];  int mgv2 = mg_get_var(postData, strlen(postData), "Name", rName, 1024);
1185   char rStartTime[20];  int mgv3 = mg_get_var(postData, strlen(postData), "StartTime", rStartTime, 20);
1186   char rStopTime[20];  int mgv4 = mg_get_var(postData, strlen(postData), "StopTime", rStopTime, 20);
1187   char rWeekDays[50];  int mgv5 = mg_get_var(postData, strlen(postData), "WeekDays", rWeekDays, 20);
1188   char tNewActive[20];  int mgv6 = mg_get_var(postData, strlen(postData), "SetActive", tNewActive, 20);
1189
1190   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) || (mgv6 == -1))
1191   {
1192     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5, mgv6);
1193     js["Result"] = false;
1194     js["Error"] = "Bad request parameters";
1195     return true;
1196   }
1197
1198   log->log("JSONServer", Log::DEBUG, "timersetactive: %s %s:%s:%s:%s:%s", tNewActive, rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1199
1200   cTimer* timer = jsonserver_findTimer(rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1201   if (timer)
1202   {
1203     if (strcmp(tNewActive, "true") == 0)
1204     {
1205       timer->SetFlags(tfActive);
1206     }
1207     else if (strcmp(tNewActive, "false") == 0)
1208     {
1209       timer->ClrFlags(tfActive);
1210     }
1211     else
1212     {
1213       js["Result"] = false;
1214       js["Error"] = "Bad request parameters";
1215       return true;
1216     }
1217
1218     js["Result"] = true;
1219
1220     Timers.SetModified();
1221
1222     return true;
1223   }
1224
1225   js["Result"] = false;
1226   js["Error"] = "Timer not found";
1227   return true;
1228 }
1229
1230 cTimer* jsonserver_findTimer(const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays)
1231 {
1232   Log* log = Log::getInstance();
1233   
1234   int numTimers = Timers.Count();
1235   cTimer* timer;
1236   for (int i = 0; i < numTimers; i++)
1237   {
1238     timer = Timers.Get(i);
1239
1240     log->log("JSONServer", Log::DEBUG, "findtimer current: %s", (const char*)timer->ToText(true));
1241     log->log("JSONServer", Log::DEBUG, "findtimer: %s", (const char*)timer->Channel()->GetChannelID().ToString());
1242     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rChannelID);
1243     log->log("JSONServer", Log::DEBUG, "findtimer: %s", timer->File());
1244     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rName);
1245     log->log("JSONServer", Log::DEBUG, "findtimer: %i", timer->StartTime());
1246     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rStartTime);
1247     log->log("JSONServer", Log::DEBUG, "findtimer: %i", timer->StopTime());
1248     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rStopTime);
1249     log->log("JSONServer", Log::DEBUG, "findtimer: %i", timer->WeekDays());
1250     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rWeekDays);
1251     
1252     if (
1253             (strcmp(timer->Channel()->GetChannelID().ToString(), rChannelID) == 0)
1254          && (strcmp(timer->File(), rName) == 0)
1255          && (timer->StartTime() == atoi(rStartTime))
1256          && (timer->StopTime() == atoi(rStopTime))
1257          && (timer->WeekDays() == atoi(rWeekDays))
1258        )
1259     {
1260       log->log("JSONServer", Log::DEBUG, "found");
1261       return timer;
1262     }
1263   }
1264   log->log("JSONServer", Log::DEBUG, "no timer found");
1265   return NULL;
1266 }
1267
1268 bool jsonserver_timerdel(Json::Value& js, const char* postData)
1269 {
1270   Log* log = Log::getInstance();
1271   log->log("JSONServer", Log::DEBUG, "timerdel");
1272   
1273   char rChannelID[50];  int mgv1 = mg_get_var(postData, strlen(postData), "ChannelID", rChannelID, 50);
1274   char rName[1024];  int mgv2 = mg_get_var(postData, strlen(postData), "Name", rName, 1024);
1275   char rStartTime[20];  int mgv3 = mg_get_var(postData, strlen(postData), "StartTime", rStartTime, 20);
1276   char rStopTime[20];  int mgv4 = mg_get_var(postData, strlen(postData), "StopTime", rStopTime, 20);
1277   char rWeekDays[50];  int mgv5 = mg_get_var(postData, strlen(postData), "WeekDays", rWeekDays, 20);
1278   
1279   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1))
1280   {
1281     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
1282     js["Result"] = false;
1283     js["Error"] = "Bad request parameters";
1284     return true;
1285   }
1286   
1287   log->log("JSONServer", Log::DEBUG, "timerdel: %s:%s:%s:%s:%s", rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1288   
1289   if (Timers.BeingEdited())
1290   {
1291     log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1292     js["Result"] = false;
1293     js["Error"] = "Timers being edited at VDR";
1294     return true;
1295   }
1296
1297   cTimer* timer = jsonserver_findTimer(rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1298   if (timer)
1299   {
1300     if (timer->Recording())
1301     {
1302       log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
1303       js["Result"] = false;
1304       js["Error"] = "Timer is running";
1305       return true;
1306     }
1307
1308     // delete
1309
1310     Timers.Del(timer);
1311     Timers.SetModified();
1312     js["Result"] = true;
1313     return true;
1314   }
1315   
1316   js["Result"] = false;
1317   js["Error"] = "Timer not found";
1318   return true;
1319 }
1320
1321 bool jsonserver_timerisrecording(Json::Value& js, const char* postData)
1322 {
1323   Log* log = Log::getInstance();
1324   log->log("JSONServer", Log::DEBUG, "timerisrecording");
1325
1326   char rChannelID[50];  int mgv1 = mg_get_var(postData, strlen(postData), "ChannelID", rChannelID, 50);
1327   char rName[1024];  int mgv2 = mg_get_var(postData, strlen(postData), "Name", rName, 1024);
1328   char rStartTime[20];  int mgv3 = mg_get_var(postData, strlen(postData), "StartTime", rStartTime, 20);
1329   char rStopTime[20];  int mgv4 = mg_get_var(postData, strlen(postData), "StopTime", rStopTime, 20);
1330   char rWeekDays[50];  int mgv5 = mg_get_var(postData, strlen(postData), "WeekDays", rWeekDays, 20);
1331
1332   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1))
1333   {
1334     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
1335     js["Result"] = false;
1336     js["Error"] = "Bad request parameters";
1337     return true;
1338   }
1339   
1340   log->log("JSONServer", Log::DEBUG, "timerisrecording: %s:%s:%s:%s:%s", rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1341   
1342   cTimer* timer = jsonserver_findTimer(rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1343   if (timer)
1344   {
1345     js["Recording"] = timer->Recording();
1346     js["Pending"] = timer->Pending();
1347     js["Result"] = true;
1348     return true;
1349   }
1350   
1351   js["Result"] = false;
1352   js["Error"] = "Timer not found";
1353   return true;
1354 }
1355
1356 bool jsonserver_tunersstatus(Json::Value& js, const char* postData)
1357 {
1358   Log* log = Log::getInstance();
1359   log->log("JSONServer", Log::DEBUG, "tunerstatus");
1360   
1361   js["NumDevices"] = cDevice::NumDevices();
1362
1363   Json::Value jsdevices(Json::arrayValue);
1364   
1365   for (int i = 0; i < cDevice::NumDevices(); i++)
1366   {
1367     Json::Value oneDevice;
1368     cDevice *d = cDevice::GetDevice(i);
1369     oneDevice["Number"] = d->DeviceNumber();
1370     oneDevice["Type"] = (const char*)d->DeviceType();
1371     oneDevice["Name"] = (const char*)d->DeviceName();
1372     oneDevice["IsPrimary"] = d->IsPrimaryDevice();
1373
1374     const cChannel* cchannel = d->GetCurrentlyTunedTransponder();
1375     if (cchannel)
1376     {
1377       oneDevice["Frequency"] = cchannel->Frequency();
1378       oneDevice["SignalStrength"] = d->SignalStrength();
1379       oneDevice["SignalQuality"] = d->SignalQuality();
1380
1381     }
1382     else
1383     {
1384       oneDevice["Frequency"] = 0;
1385       oneDevice["SignalStrength"] = 0;
1386       oneDevice["SignalQuality"] = 0;
1387     }
1388     
1389     jsdevices.append(oneDevice);
1390   }
1391   
1392   js["Devices"] = jsdevices;
1393
1394
1395   Json::Value jstimers(Json::arrayValue);
1396   int numTimers = Timers.Count();
1397   cTimer* timer;
1398   for (int i = 0; i < numTimers; i++)
1399   {
1400     timer = Timers.Get(i);
1401
1402     if (timer->Recording())
1403     {
1404       Json::Value oneTimer;
1405       oneTimer["Recording"] = timer->Recording();
1406       oneTimer["StartTime"] = (int)timer->StartTime();
1407       oneTimer["StopTime"] = (int)timer->StopTime();
1408       oneTimer["File"] = timer->File();
1409
1410       cRecordControl* crc = cRecordControls::GetRecordControl(timer);
1411       if (crc)
1412       {
1413         cDevice* crcd = crc->Device();
1414         oneTimer["DeviceNumber"] = crcd->DeviceNumber();
1415       }
1416       else
1417       {
1418         oneTimer["DeviceNumber"] = Json::Value::null;
1419       }
1420
1421       const cChannel* channel = timer->Channel();
1422       if (channel)
1423       {
1424         oneTimer["ChannelName"] = channel->Name();
1425       }
1426       else
1427       {
1428         oneTimer["ChannelName"] = Json::Value::null;
1429       }
1430
1431       jstimers.append(oneTimer);
1432     }
1433       
1434   }
1435   js["CurrentRecordings"] = jstimers;
1436
1437   
1438   js["Result"] = true;
1439   return true;
1440 }