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