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