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