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