]> git.vomp.tv Git - jsonserver.git/blob - handler.c
Add download-all-EPG 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, "timeredit")) success = jsonserver_timeredit(js, postData);
89   else if (!strcmp(wvrequest, "tunersstatus")) success = jsonserver_tunersstatus(js, postData);
90   else if (!strcmp(wvrequest, "epgsearchsame")) success = jsonserver_epgsearchsame(js, postData);
91   else if (!strcmp(wvrequest, "epgdownload")) success = jsonserver_epgdownload(js, postData);
92
93   if (!success) return 0; // the specific handler failed badly
94
95   // Now js will be filled
96
97   Json::StyledWriter sw;
98   std::string jsonout = sw.write(js);
99   mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
100   mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
101   mg_write(conn, jsonout.c_str(), jsonout.length());
102   return 1;
103
104   
105 /*
106   else if (event == MG_EVENT_LOG)
107   {
108     if (request_info->status_code == 400) // bad request
109     {
110       log->log("Mongoose", Log::DEBUG, "400 BAD REQUEST:");
111       log->log("Mongoose", Log::DEBUG, request_info->request_method);
112       log->log("Mongoose", Log::DEBUG, request_info->uri);
113       log->log("Mongoose", Log::DEBUG, request_info->http_version);
114       log->log("Mongoose", Log::DEBUG, request_info->query_string);
115       log->log("Mongoose", Log::DEBUG, request_info->log_message);
116       for (int i = 0; i < request_info->num_headers; i++)
117       {
118         log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
119       }
120     }
121     else
122     {
123       log->log("Mongoose", Log::DEBUG, request_info->log_message);
124       log->log("Mongoose", Log::DEBUG, request_info->uri);
125     }
126     return (void*)1;
127   }
128   
129   // other events not handled:
130   // MG_HTTP_ERROR, MG_INIT_SSL
131   // Let mongoose do something with those
132
133   return NULL;
134
135 */
136   
137 }
138
139 bool jsonserver_gettime(Json::Value& js)
140 {
141   Log* log = Log::getInstance();
142   log->log("JSONServer", Log::DEBUG, "gettime");
143
144   struct timeval tv;
145   gettimeofday(&tv, NULL);
146   
147   js["Time"] = (Json::UInt64)tv.tv_sec;
148   js["MTime"] = (Json::UInt)(tv.tv_usec/1000);
149   js["Result"] = true;
150   return true;
151 }
152
153 bool jsonserver_diskstats(Json::Value& js)
154 {
155   Log* log = Log::getInstance();
156   log->log("JSONServer", Log::DEBUG, "diskstats");
157   
158   int FreeMB;
159   int UsedMB;
160
161 #if APIVERSNUM > 20101
162   int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB, &UsedMB);
163 #else
164   int Percent = VideoDiskSpace(&FreeMB, &UsedMB);
165 #endif
166   
167   js["FreeMiB"] = FreeMB;
168   js["UsedMiB"] = UsedMB;
169   js["Percent"] = Percent;
170   
171   js["Result"] = true;
172   return true;
173 }
174
175 bool jsonserver_reclist(Json::Value& js)
176 {
177   Log* log = Log::getInstance();
178   log->log("JSONServer", Log::DEBUG, "reclist");
179
180   Json::Value jsrecordings(Json::arrayValue);
181   cRecordings Recordings;
182   Recordings.Load();
183   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
184   {
185     Json::Value oneRec;
186     oneRec["StartTime"] = (Json::UInt)recording->Start();
187     oneRec["Length"] = (Json::UInt)recording->LengthInSeconds();
188     oneRec["IsNew"] = recording->IsNew();
189     oneRec["Name"] = recording->Name();
190     oneRec["Filename"] = recording->FileName();
191     oneRec["FileSizeMB"] = recording->FileSizeMB();
192
193     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
194     if (rc) oneRec["CurrentlyRecording"] = true;
195     else    oneRec["CurrentlyRecording"] = false;
196     
197     jsrecordings.append(oneRec);
198   }
199   js["Recordings"] = jsrecordings;
200   
201   return true;
202 }
203
204 bool jsonserver_recinfo(Json::Value& js, const char* postData)
205 {
206   Log* log = Log::getInstance();
207   log->log("JSONServer", Log::DEBUG, "recinfo");
208
209   char reqfilename[1000];
210   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
211   if (mgv1 == -1)
212   {
213     log->log("JSONServer", Log::ERR, "Could not decode filename");
214     js["Result"] = false;
215     js["Error"] = "Could not decode filename";
216     return true;
217   }
218
219   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
220
221   cRecordings Recordings;
222   Recordings.Load(); // probably have to do this
223   cRecording *recording = Recordings.GetByName(reqfilename);
224
225   if (!recording)
226   {
227     log->log("JSONServer", Log::ERR, "recinfo found no recording");
228     js["Result"] = false;
229     return true;
230   }
231
232   js["IsNew"] = recording->IsNew();
233   js["LengthInSeconds"] = recording->LengthInSeconds();
234   js["FileSizeMB"] = recording->FileSizeMB();
235   js["Name"] = recording->Name() ? recording->Name() : Json::Value::null;
236   js["Priority"] = recording->Priority();
237   js["LifeTime"] = recording->Lifetime();
238   js["Start"] = (Json::UInt)recording->Start();
239
240   js["CurrentlyRecordingStart"] = 0;
241   js["CurrentlyRecordingStop"] = 0;
242   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
243   if (rc)
244   {
245     js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
246     js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
247   }
248
249   js["ResumePoint"] = 0;
250
251   const cRecordingInfo *info = recording->Info();
252   if (info)
253   {
254     js["ChannelName"] = info->ChannelName() ? info->ChannelName() : Json::Value::null;
255     js["Title"] = info->Title() ? info->Title() : Json::Value::null;
256     js["ShortText"] = info->ShortText() ? info->ShortText() : Json::Value::null;
257     js["Description"] = info->Description() ? info->Description() : Json::Value::null;
258
259     const cComponents* components = info->Components();
260     if (!components)
261     {
262       js["Components"] = Json::Value::null;
263     }
264     else
265     {
266       Json::Value jscomponents;
267
268       tComponent* component;
269       for (int i = 0; i < components->NumComponents(); i++)
270       {
271         component = components->Component(i);
272
273         Json::Value oneComponent;
274         oneComponent["Stream"] = component->stream;
275         oneComponent["Type"] = component->type;
276         oneComponent["Language"] = component->language ? component->language : Json::Value::null;
277         oneComponent["Description"] = component->description ? component->description : Json::Value::null;
278         jscomponents.append(oneComponent);
279       }
280
281       js["Components"] = jscomponents;
282     }
283
284     cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
285     if (ResumeFile.Read() >= 0) js["ResumePoint"] = floor(ResumeFile.Read() / info->FramesPerSecond());
286   }
287
288   js["Result"] = true;
289   return true;
290 }
291
292 bool jsonserver_recstop(Json::Value& js, const char* postData)
293 {
294   Log* log = Log::getInstance();
295   log->log("JSONServer", Log::DEBUG, "recstop");
296   
297   char reqfilename[1000];
298   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
299   if (mgv1 == -1)
300   {
301     log->log("JSONServer", Log::ERR, "Could not decode filename");
302     js["Result"] = false;
303     js["Error"] = "Could not decode filename";
304     return true;
305   }
306   
307   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
308   
309   cRecordings Recordings;
310   Recordings.Load(); // probably have to do this
311   cRecording *recording = Recordings.GetByName(reqfilename);
312   
313   if (!recording)
314   {
315     log->log("JSONServer", Log::ERR, "recstop found no recording");
316     js["Result"] = false;
317     return true;
318   }
319
320   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
321   if (!rc)
322   {
323     log->log("JSONServer", Log::ERR, "recstop - not currently recording");
324     js["Result"] = false;
325     return true;
326   }
327
328   if (Timers.BeingEdited())
329   {
330     log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
331     js["Result"] = false;
332     return true;
333   }
334
335   cTimer* timer = rc->Timer();
336   if (!timer)
337   {
338     log->log("JSONServer", Log::ERR, "recstop - timer not found");
339     js["Result"] = false;
340     return true;
341   }
342   
343   timer->ClrFlags(tfActive);
344   Timers.SetModified();
345   
346   js["Result"] = true;
347   return true;
348 }  
349   
350 bool jsonserver_recdel(Json::Value& js, const char* postData)
351 {
352   Log* log = Log::getInstance();
353   log->log("JSONServer", Log::DEBUG, "recdel");
354
355   char reqfilename[1000];
356   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
357   if (mgv1 == -1)
358   {
359     log->log("JSONServer", Log::ERR, "Could not decode filename");
360     js["Result"] = false;
361     js["Error"] = "Could not decode filename";
362     return true;
363   }
364
365   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
366   
367   cRecordings Recordings;
368   Recordings.Load(); // probably have to do this
369   cRecording *recording = Recordings.GetByName(reqfilename);
370
371   if (!recording)
372   {
373     js["Result"] = false;
374     js["Error"] = "Could not find recording to delete";
375     return true;
376   }
377
378   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
379   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
380   if (rc)
381   {
382     js["Result"] = false;
383     js["Error"] = "This recording is still recording.. ho ho";
384     return true;
385   }
386
387   if (recording->Delete())
388   {
389     ::Recordings.DelByName(recording->FileName());
390     js["Result"] = true;
391   }
392   else
393   {
394     js["Result"] = false;
395     js["Error"] = "Failed to delete recording";
396   }
397
398   return true;
399 }
400
401 bool jsonserver_recmove(Json::Value& js, const char* postData)
402 {
403   Log* log = Log::getInstance();
404   log->log("JSONServer", Log::DEBUG, "recmove");
405
406   char* fileNameToMove = NULL;
407   char* requestedNewPath = NULL;
408   char* dateDirName = NULL;
409   char* titleDirName = NULL;
410   char* folderName = NULL;
411   char* newContainer = NULL;
412   char* newDir = NULL;
413   
414   try
415   {
416     int postDataLen = strlen(postData)+1;
417     fileNameToMove = new char[postDataLen];
418     int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToMove, postDataLen);
419     requestedNewPath = new char[postDataLen];
420     int mgv2 = mg_get_var(postData, postDataLen-1, "newpath", requestedNewPath, postDataLen);
421
422     if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToMove) || !strlen(requestedNewPath))
423     {
424       log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
425       throw 1;
426     }
427
428     cRecordings Recordings;
429     Recordings.Load(); // probably have to do this
430     cRecording* recordingObj = Recordings.GetByName(fileNameToMove);
431     if (!recordingObj) throw 2;
432     
433     cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
434     if (rc) throw 3;
435
436     log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->Name());
437     log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->FileName());
438     log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewPath);
439
440     const char* t = recordingObj->FileName();
441
442     int k, j, m;
443
444     // Find the datedirname
445     for(k = strlen(t) - 1; k >= 0; k--)
446     {
447       if (t[k] == '/')
448       {
449         log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
450         dateDirName = new char[strlen(&t[k+1]) + 1];
451         strcpy(dateDirName, &t[k+1]);
452         break;
453       }
454     }
455
456     // Find the titledirname
457
458     for(j = k-1; j >= 0; j--)
459     {
460       if (t[j] == '/')
461       {
462         log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
463         titleDirName = new char[k - j];
464         memcpy(titleDirName, &t[j+1], k - j - 1);
465         titleDirName[k - j - 1] = '\0';
466         break;
467       }
468     }
469
470     // Find the foldername
471
472 #if APIVERSNUM > 20101
473     const char* vidDirStr = cVideoDirectory::Name();
474 #else
475     const char* vidDirStr = VideoDirectory;
476 #endif
477     int vidDirStrLen = strlen(vidDirStr);
478
479     log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, vidDirStrLen);
480     if (j > vidDirStrLen) // Rec is in a subfolder now
481     {
482       for(m = j-1; m >= 0; m--)
483       {
484         if (t[m] == '/')
485         {
486           log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
487           folderName = new char[j - m];
488           memcpy(folderName, &t[m+1], j - m - 1);
489           folderName[j - m - 1] = '\0';
490           break;
491         }
492       }
493     }
494
495     ExchangeChars(requestedNewPath, true);
496
497     log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
498     log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
499     log->log("JSONServer", Log::DEBUG, "viddir: %s", vidDirStr);
500     if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
501     log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewPath);
502
503     // Could be a new path - construct that first and test
504     newContainer = new char[vidDirStrLen + strlen(requestedNewPath) + strlen(titleDirName) + 1];
505     sprintf(newContainer, "%s%s", vidDirStr, requestedNewPath);
506     log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
507     struct stat dstat;
508     int statret = stat(newContainer, &dstat);
509     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
510     {
511       log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
512       int mkdirret = mkdir(newContainer, 0755);
513       if (mkdirret != 0) throw 4;
514     }
515     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
516     {
517       // Something exists but it's not a dir
518       throw 5;
519     }
520
521     // New path now created or was there already
522
523     sprintf(newContainer, "%s%s%s", vidDirStr, requestedNewPath, titleDirName);
524     log->log("JSONServer", Log::DEBUG, "%s", newContainer);
525
526     statret = stat(newContainer, &dstat);
527     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
528     {
529       log->log("JSONServer", Log::DEBUG, "new dir does not exist (2)");
530       int mkdirret = mkdir(newContainer, 0755);
531       if (mkdirret != 0) throw 6;
532     }
533     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
534     {
535       // Something exists but it's not a dir
536       throw 7;
537     }
538
539     // Ok, the directory container has been made, or it pre-existed.
540
541     newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
542     sprintf(newDir, "%s/%s", newContainer, dateDirName);
543
544     log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
545     if (rename(t, newDir) != 0) throw 8;
546     
547     // Success. Test for remove old dir containter
548     char* tempOldTitleDir = new char[k+1];
549     memcpy(tempOldTitleDir, t, k);
550     tempOldTitleDir[k] = '\0';
551     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
552     rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
553     delete[] tempOldTitleDir;
554
555     // Test for remove old foldername
556     if (folderName)
557     {
558       char* tempOldFolderName = new char[j+1];
559       memcpy(tempOldFolderName, t, j);
560       tempOldFolderName[j] = '\0';
561       log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldfoldername: %s", j+1, j, strlen(tempOldFolderName), tempOldFolderName);
562       /*
563       DESCRIPTION
564       rmdir() deletes a directory, which must be empty.
565       ENOTEMPTY - pathname  contains  entries  other than . and ..
566       So, should be safe to call rmdir on non-empty dir
567       */
568       rmdir(tempOldFolderName); // can't do anything about a fail result at this point.
569       delete[] tempOldFolderName;
570     }
571
572     ::Recordings.Update();
573     js["Result"] = true;
574     js["NewRecordingFileName"] = newDir;
575   }
576   catch (int e)
577   {
578     js["Result"] = false;
579     if (e == 1)
580     {
581       log->log("JSONServer", Log::ERR, "Bad parameters");
582       js["Error"] = "Bad request parameters";
583     }
584     else if (e == 2)
585     {
586       log->log("JSONServer", Log::ERR, "Could not find recording to move");
587       js["Error"] = "Bad filename";
588     }
589     else if (e == 3)
590     {
591       log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
592       js["Error"] = "Cannot move recording in progress";
593     }
594     else if (e == 4)
595     {
596       log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
597       js["Error"] = "Failed to create new directory (1)";
598     }
599     else if (e == 5)
600     {
601       log->log("JSONServer", Log::ERR, "Something already exists? (1)");
602       js["Error"] = "Something already exists at the new path (1)";
603     }
604     else if (e == 6)
605     {
606       log->log("JSONServer", Log::ERR, "Failed to make new dir (2)");
607       js["Error"] = "Failed to create new directory (2)";
608     }
609     else if (e == 7)
610     {
611       log->log("JSONServer", Log::ERR, "Something already exists?");
612       js["Error"] = "Something already exists at the new path";
613     }
614     else if (e == 8)
615     {
616       log->log("JSONServer", Log::ERR, "Rename failed");
617       js["Error"] = "Move failed";
618     }
619   }
620
621   if (fileNameToMove)   delete[] fileNameToMove;
622   if (requestedNewPath) delete[] requestedNewPath;
623   if (dateDirName)      delete[] dateDirName;
624   if (titleDirName)     delete[] titleDirName;
625   if (folderName)       delete[] folderName;
626   if (newContainer)     delete[] newContainer;
627   if (newDir)           delete[] newDir;
628
629   return true;
630 }
631
632 bool jsonserver_recrename(Json::Value& js, const char* postData)
633 {
634   Log* log = Log::getInstance();
635   log->log("JSONServer", Log::DEBUG, "recrename");
636   
637   char* fileNameToRename = NULL;
638   char* requestedNewName = NULL;
639   char* dateDirName = NULL;
640   char* titleDirName = NULL;
641   char* folderName = NULL;
642   char* newContainer = NULL;
643   char* newDir = NULL;
644   
645   try
646   {
647     int postDataLen = strlen(postData)+1;
648     fileNameToRename = new char[postDataLen];
649     int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToRename, postDataLen);
650     requestedNewName = new char[postDataLen];
651     int mgv2 = mg_get_var(postData, postDataLen-1, "newname", requestedNewName, postDataLen);
652     
653     if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToRename) || !strlen(requestedNewName))
654     {
655       log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
656       throw 1;
657     }
658     
659     cRecordings Recordings;
660     Recordings.Load(); // probably have to do this
661     cRecording* recordingObj = Recordings.GetByName(fileNameToRename);
662     if (!recordingObj) throw 2;
663     
664     cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
665     if (rc) throw 3;
666     
667     log->log("JSONServer", Log::DEBUG, "renaming recording: %s", recordingObj->Name());
668     log->log("JSONServer", Log::DEBUG, "renaming recording: %s", recordingObj->FileName());
669     log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewName);
670     
671     const char* t = recordingObj->FileName();
672     
673     int k, j, m;
674     
675     // Find the datedirname
676     for(k = strlen(t) - 1; k >= 0; k--)
677     {
678       if (t[k] == '/')
679       {
680         log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
681         dateDirName = new char[strlen(&t[k+1]) + 1];
682         strcpy(dateDirName, &t[k+1]);
683         break;
684       }
685     }
686     
687     // Find the titledirname
688     
689     for(j = k-1; j >= 0; j--)
690     {
691       if (t[j] == '/')
692       {
693         log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
694         titleDirName = new char[k - j];
695         memcpy(titleDirName, &t[j+1], k - j - 1);
696         titleDirName[k - j - 1] = '\0';
697         break;
698       }
699     }
700     
701     // Find the foldername
702
703 #if APIVERSNUM > 20101
704     const char* vidDirStr = cVideoDirectory::Name();
705 #else
706     const char* vidDirStr = VideoDirectory;
707 #endif
708     int vidDirStrLen = strlen(vidDirStr);
709
710     log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, vidDirStrLen);
711     if (j > vidDirStrLen) // Rec is in a subfolder now
712     {
713       for(m = j-1; m >= 0; m--)
714       {
715         if (t[m] == '/')
716         {
717           log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
718           folderName = new char[j - m];
719           memcpy(folderName, &t[m+1], j - m - 1);
720           folderName[j - m - 1] = '\0';
721           break;
722         }
723       }
724     }
725     
726     ExchangeChars(requestedNewName, true);
727     
728     log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
729     log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
730     log->log("JSONServer", Log::DEBUG, "viddir: %s", vidDirStr);
731     if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
732     log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewName);
733    
734     // Could be a new path - construct that first and test
735
736     if (folderName)
737     {
738       newContainer = new char[vidDirStrLen + 1 + strlen(folderName) + 1 + strlen(requestedNewName) + 1];
739       sprintf(newContainer, "%s/%s/%s", vidDirStr, folderName, requestedNewName);
740     }
741     else
742     {
743       newContainer = new char[vidDirStrLen + 1 + strlen(requestedNewName) + 1];
744       sprintf(newContainer, "%s/%s", vidDirStr, requestedNewName);
745     }
746     log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
747     struct stat dstat;
748     int statret = stat(newContainer, &dstat);
749     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
750     {
751       log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
752       int mkdirret = mkdir(newContainer, 0755);
753       if (mkdirret != 0) throw 4;
754     }
755     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
756     {
757       // Something exists but it's not a dir
758       throw 5;
759     }
760     
761     // New path now created or was there already
762     
763     newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
764     sprintf(newDir, "%s/%s", newContainer, dateDirName);
765     
766     log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
767     if (rename(t, newDir) != 0) throw 8;
768     
769     // Success. Test for remove old dir containter
770     char* tempOldTitleDir = new char[k+1];
771     memcpy(tempOldTitleDir, t, k);
772     tempOldTitleDir[k] = '\0';
773     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
774     rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
775     delete[] tempOldTitleDir;
776     
777     ::Recordings.Update();
778     js["Result"] = true;
779     js["NewRecordingFileName"] = newDir;
780   }
781   catch (int e)
782   {
783     js["Result"] = false;
784     if (e == 1)
785     {
786       log->log("JSONServer", Log::ERR, "Bad parameters");
787       js["Error"] = "Bad request parameters";
788     }
789     else if (e == 2)
790     {
791       log->log("JSONServer", Log::ERR, "Could not find recording to move");
792       js["Error"] = "Bad filename";
793     }
794     else if (e == 3)
795     {
796       log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
797       js["Error"] = "Cannot move recording in progress";
798     }
799     else if (e == 4)
800     {
801       log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
802       js["Error"] = "Failed to create new directory (1)";
803     }
804     else if (e == 5)
805     {
806       log->log("JSONServer", Log::ERR, "Something already exists? (1)");
807       js["Error"] = "Something already exists at the new path (1)";
808     }
809     else if (e == 8)
810     {
811       log->log("JSONServer", Log::ERR, "Rename failed");
812       js["Error"] = "Move failed";
813     }
814   }
815   
816   if (fileNameToRename) delete[] fileNameToRename;
817   if (requestedNewName) delete[] requestedNewName;
818   if (dateDirName)      delete[] dateDirName;
819   if (titleDirName)     delete[] titleDirName;
820   if (folderName)       delete[] folderName;
821   if (newContainer)     delete[] newContainer;
822   if (newDir)           delete[] newDir;
823   
824   return true;
825 }
826
827 bool jsonserver_recresetresume(Json::Value& js, const char* postData)
828 {
829   Log* log = Log::getInstance();
830   log->log("JSONServer", Log::DEBUG, "recresetresume");
831
832   char reqfilename[1000];
833   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
834   if (mgv1 == -1)
835   {
836     log->log("JSONServer", Log::ERR, "Could not decode filename");
837     js["Result"] = false;
838     js["Error"] = "Could not decode filename";
839     return true;
840   }
841
842   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
843
844   cRecordings Recordings;
845   Recordings.Load(); // probably have to do this
846   cRecording *recording = Recordings.GetByName(reqfilename);
847
848   if (!recording)
849   {
850     js["Result"] = false;
851     js["Error"] = "Could not find recording to reset resume";
852     return true;
853   }
854
855   log->log("JSONServer", Log::DEBUG, "Reset resume for: %s", recording->Name());
856
857   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
858   if (ResumeFile.Read() >= 0)
859   {
860     ResumeFile.Delete();
861     js["Result"] = true;
862     return true;
863   }
864   else
865   {
866     js["Result"] = false;
867     js["Error"] = "Recording has no resume point";
868     return true;
869   }
870 }
871
872 bool jsonserver_channellist(Json::Value& js)
873 {
874   Log* log = Log::getInstance();
875   log->log("JSONServer", Log::DEBUG, "channellist");
876
877   Json::Value jschannels(Json::arrayValue);
878   
879 //  int type;
880   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
881   {
882     if (!channel->GroupSep())
883     {
884 //      log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
885
886 //      if (channel->Vpid()) type = 1;
887 //      else if (channel->Apid(0)) type = 2;
888 //      else continue;
889
890       Json::Value oneChannel;
891       oneChannel["ID"] = (const char *)channel->GetChannelID().ToString();
892       oneChannel["Number"] = channel->Number();
893 //      oneChannel["Type"] = type;
894       oneChannel["Name"] = channel->Name();
895 //#if VDRVERSNUM < 10703
896 //      oneChannel["VType"] = 2;
897 //#else
898 //      oneChannel["VType"] = channel->Vtype();
899 //#endif
900       jschannels.append(oneChannel);    
901     }
902   }
903   js["Channels"] = jschannels;
904   
905   return true;
906 }
907
908 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
909 {
910   Log* log = Log::getInstance();
911   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
912
913   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);  
914   char sStartTime[15];      int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);  
915   char sDuration[15];       int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);  
916
917   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
918   {
919     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
920     js["Result"] = false;
921     js["Error"] = "Bad request parameters";
922     return true;
923   }
924
925   int channelNumber = atoi(sChannelNumber);
926   int startTime = atoi(sStartTime); 
927   int duration = atoi(sDuration); 
928
929   cChannel* channel = NULL;
930   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
931   {
932     if (channel->GroupSep()) continue;
933     if (channel->Number() == channelNumber) break;
934   }
935
936   if (!channel)
937   {
938     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
939     js["Result"] = false;
940     js["Error"] = "Could not find channel";
941     return true;
942   }
943
944   cSchedulesLock MutexLock;
945   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
946   if (!Schedules)
947   {
948     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
949     js["Result"] = false;
950     js["Error"] = "Internal schedules error (1)";
951     return true;
952   }
953   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
954   if (!Schedule)     
955   {
956     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
957     js["Result"] = false;
958     js["Error"] = "Internal schedules error (2)";
959     return true;
960   }
961     
962   Json::Value jsevents(Json::arrayValue);
963
964   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
965   {
966     //in the past filter
967     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
968    //start time filter
969     if ((event->StartTime() + event->Duration()) <= startTime) continue;
970     //duration filter
971     if (event->StartTime() >= (startTime + duration)) continue;
972
973     Json::Value oneEvent;
974     oneEvent["ID"] = event->EventID();
975     oneEvent["Time"] = (Json::UInt)event->StartTime();
976     oneEvent["Duration"] = event->Duration();
977     oneEvent["Title"] = event->Title() ? event->Title() : "";
978     oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
979     oneEvent["HasTimer"] = event->HasTimer();
980     //oneEvent["Description"] = event->Description() ? event->Description() : "";
981     jsevents.append(oneEvent);
982   }
983
984   js["Result"] = true;
985   js["Events"] = jsevents;
986   return true;
987 }
988
989 bool jsonserver_getscheduleevent(Json::Value& js, const char* postData)
990 {
991   Log* log = Log::getInstance();
992   log->log("JSONServer", Log::DEBUG, "getscheduleevent '%s'", postData);
993   
994   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);
995   char sEventID[15];        int mgv2 = mg_get_var(postData, strlen(postData), "eventid", sEventID, 15);
996   
997   if ( (mgv1 == -1) || (mgv2 == -1) )
998   {
999     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
1000     js["Result"] = false;
1001     js["Error"] = "Bad request parameters";
1002     return true;
1003   }
1004
1005   int channelNumber = atoi(sChannelNumber);
1006   int eventID = atoi(sEventID);
1007   
1008   const cEvent* event = jsonserver_getEvent(js, channelNumber, eventID, 0);
1009   if (!event)
1010   {
1011     js["Result"] = false;
1012     return true;
1013   }
1014   
1015   Json::Value oneEvent;
1016   oneEvent["ID"] = event->EventID();
1017   oneEvent["Time"] = (Json::UInt)event->StartTime();
1018   oneEvent["Duration"] = event->Duration();
1019   oneEvent["Title"] = event->Title() ? event->Title() : "";
1020   oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
1021   oneEvent["Description"] = event->Description() ? event->Description() : "";
1022   oneEvent["HasTimer"] = event->HasTimer();
1023   oneEvent["RunningStatus"] = event->RunningStatus();
1024
1025   js["Result"] = true;
1026   js["Event"] = oneEvent;
1027   return true;
1028 }
1029
1030 const cEvent* jsonserver_getEvent(Json::Value& js, int channelNumber, int eventID, int aroundTime)
1031 {
1032   Log* log = Log::getInstance();
1033   
1034   cChannel* channel = NULL;
1035   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
1036   {
1037     if (channel->GroupSep()) continue;
1038     if (channel->Number() == channelNumber) break;
1039   }
1040
1041   if (!channel)
1042   {
1043     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
1044     js["Error"] = "Could not find channel";
1045     return NULL;
1046   }
1047
1048   cSchedulesLock MutexLock;
1049   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1050   if (!Schedules)
1051   {
1052     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
1053     js["Error"] = "Internal schedules error (1)";
1054     return NULL;
1055   }
1056   
1057   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1058   if (!Schedule)
1059   {
1060     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
1061     js["Error"] = "Internal schedules error (2)";
1062     return NULL;
1063   }
1064   
1065   const cEvent* event = NULL;
1066   if (eventID)
1067   {
1068     event = Schedule->GetEvent(eventID);
1069   }
1070   else
1071   {
1072     event = Schedule->GetEventAround(aroundTime);
1073   }
1074   
1075   if (!event)
1076   {
1077     log->log("JSONServer", Log::ERR, "Could not find requested event: %i", eventID);
1078     js["Error"] = "Internal schedules error (3)";
1079     return NULL;
1080   }
1081
1082   return event;
1083 }
1084
1085 bool jsonserver_timerlist(Json::Value& js)
1086 {
1087   Log* log = Log::getInstance();
1088   log->log("JSONServer", Log::DEBUG, "timerlist");
1089
1090   Json::Value jstimers(Json::arrayValue);
1091   
1092   cTimer *timer;
1093   int numTimers = Timers.Count();
1094
1095   for (int i = 0; i < numTimers; i++)
1096   {
1097     timer = Timers.Get(i);
1098     Json::Value oneTimer;
1099     oneTimer["Active"] = timer->HasFlags(tfActive);
1100     oneTimer["Recording"] = timer->Recording();
1101     oneTimer["Pending"] = timer->Pending();
1102     oneTimer["Priority"] = timer->Priority();
1103     oneTimer["Lifetime"] = timer->Lifetime();
1104     oneTimer["ChannelNumber"] = timer->Channel()->Number();
1105     oneTimer["ChannelID"] = (const char *)timer->Channel()->GetChannelID().ToString();
1106     oneTimer["StartTime"] = (int)timer->StartTime();
1107     oneTimer["StopTime"] = (int)timer->StopTime();
1108     oneTimer["Day"] = (int)timer->Day();
1109     oneTimer["WeekDays"] = timer->WeekDays();
1110     oneTimer["Name"] = timer->File();
1111     
1112     const cEvent* event = timer->Event();
1113     if (event)
1114     {
1115       oneTimer["EventID"] = event->EventID();
1116     }
1117     else
1118     {
1119       int channelNumber = timer->Channel()->Number();
1120       int aroundTime = timer->StartTime() + 1;
1121       log->log("JSONServer", Log::DEBUG, "%i", aroundTime);
1122
1123       const cEvent* eventAround = jsonserver_getEvent(js, channelNumber, 0, aroundTime);
1124       if (eventAround)
1125       {
1126         oneTimer["EventID"] = eventAround->EventID();
1127       }
1128       else
1129       {
1130         oneTimer["EventID"] = 0;
1131       }
1132     }
1133
1134     jstimers.append(oneTimer);
1135   }
1136   
1137   js["Timers"] = jstimers;
1138   js["Result"] = true;
1139   return true;
1140 }
1141
1142 bool jsonserver_timerset(Json::Value& js, const char* postData)
1143 {
1144   Log* log = Log::getInstance();
1145   log->log("JSONServer", Log::DEBUG, "timerset");
1146
1147   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
1148
1149   if (mgv1 == -1)
1150   {
1151     log->log("JSONServer", Log::ERR, "Could not get timerstring");
1152     js["Result"] = false;
1153     js["Error"] = "Bad request parameters";
1154     return true;
1155   }
1156
1157   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
1158   cTimer *timer = new cTimer;
1159   if (!timer->Parse(sTimerString))
1160   {
1161     delete timer;
1162     js["Result"] = false;
1163     js["Error"] = "Failed to parse timer request details";
1164     return true;
1165   }
1166
1167   cTimer *t = Timers.GetTimer(timer);
1168   if (t)
1169   {
1170     delete timer;
1171     js["Result"] = false;
1172     js["Error"] = "Timer already exists";
1173     return true;
1174   }
1175
1176   Timers.Add(timer);
1177   Timers.SetModified();
1178   js["Result"] = true;
1179   return true;
1180 }
1181
1182 bool jsonserver_timersetactive(Json::Value& js, const char* postData)
1183 {
1184   Log* log = Log::getInstance();
1185   log->log("JSONServer", Log::DEBUG, "timersetactive");
1186
1187   char rChannelID[50];  int mgv1 = mg_get_var(postData, strlen(postData), "ChannelID", rChannelID, 50);
1188   char rName[1024];  int mgv2 = mg_get_var(postData, strlen(postData), "Name", rName, 1024);
1189   char rStartTime[20];  int mgv3 = mg_get_var(postData, strlen(postData), "StartTime", rStartTime, 20);
1190   char rStopTime[20];  int mgv4 = mg_get_var(postData, strlen(postData), "StopTime", rStopTime, 20);
1191   char rWeekDays[50];  int mgv5 = mg_get_var(postData, strlen(postData), "WeekDays", rWeekDays, 20);
1192   char tNewActive[20];  int mgv6 = mg_get_var(postData, strlen(postData), "SetActive", tNewActive, 20);
1193
1194   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) || (mgv6 == -1))
1195   {
1196     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5, mgv6);
1197     js["Result"] = false;
1198     js["Error"] = "Bad request parameters";
1199     return true;
1200   }
1201
1202   log->log("JSONServer", Log::DEBUG, "timersetactive: %s %s:%s:%s:%s:%s", tNewActive, rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1203
1204   cTimer* timer = jsonserver_findTimer(rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1205   if (timer)
1206   {
1207     if (strcmp(tNewActive, "true") == 0)
1208     {
1209       timer->SetFlags(tfActive);
1210     }
1211     else if (strcmp(tNewActive, "false") == 0)
1212     {
1213       timer->ClrFlags(tfActive);
1214     }
1215     else
1216     {
1217       js["Result"] = false;
1218       js["Error"] = "Bad request parameters";
1219       return true;
1220     }
1221
1222     js["Result"] = true;
1223
1224     Timers.SetModified();
1225
1226     return true;
1227   }
1228
1229   js["Result"] = false;
1230   js["Error"] = "Timer not found";
1231   return true;
1232 }
1233
1234 bool jsonserver_timeredit(Json::Value& js, const char* postData)
1235 {
1236   Log* log = Log::getInstance();
1237   log->log("JSONServer", Log::DEBUG, "timeredit");
1238
1239   // Get all olds
1240   char oldName[1024];     int mgv1 = mg_get_var(postData, strlen(postData), "OldName", oldName, 1024);
1241   char oldActive[20];     int mgv2 = mg_get_var(postData, strlen(postData), "OldActive", oldActive, 20);
1242   char oldChannelID[50];  int mgv3 = mg_get_var(postData, strlen(postData), "OldChannelID", oldChannelID, 50);
1243   char oldDay[20];        int mgv4 = mg_get_var(postData, strlen(postData), "OldDay", oldDay, 20);
1244   char oldWeekDays[50];   int mgv5 = mg_get_var(postData, strlen(postData), "OldWeekDays", oldWeekDays, 20);
1245   char oldStartTime[20];  int mgv6 = mg_get_var(postData, strlen(postData), "OldStartTime", oldStartTime, 20);
1246   char oldStopTime[20];   int mgv7 = mg_get_var(postData, strlen(postData), "OldStopTime", oldStopTime, 20);
1247   char oldPriority[20];   int mgv8 = mg_get_var(postData, strlen(postData), "OldPriority", oldPriority, 20);
1248   char oldLifetime[20];   int mgv9 = mg_get_var(postData, strlen(postData), "OldLifetime", oldLifetime, 20);
1249
1250   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) || (mgv6 == -1) || (mgv7 == -1) || (mgv8 == -1) || (mgv9 == -1))
1251   {
1252     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5, mgv6, mgv7, mgv8, mgv9);
1253     js["Result"] = false;
1254     js["Error"] = "Bad request parameters";
1255     return true;
1256   }
1257
1258   log->log("JSONServer", Log::DEBUG, "timeredit: %s %s %s %s %s %s %s %s %s", oldName, oldActive, oldChannelID, oldDay, oldWeekDays, oldStartTime, oldStopTime, oldPriority, oldLifetime);
1259
1260
1261   // Get all news
1262   char newName[1024];     int mgv11 = mg_get_var(postData, strlen(postData), "NewName", newName, 1024);
1263   char newActive[20];     int mgv12 = mg_get_var(postData, strlen(postData), "NewActive", newActive, 20);
1264   char newChannelID[50];  int mgv13 = mg_get_var(postData, strlen(postData), "NewChannelID", newChannelID, 50);
1265   char newDay[20];        int mgv14 = mg_get_var(postData, strlen(postData), "NewDay", newDay, 20);
1266   char newWeekDays[50];   int mgv15 = mg_get_var(postData, strlen(postData), "NewWeekDays", newWeekDays, 20);
1267   char newStartTime[20];  int mgv16 = mg_get_var(postData, strlen(postData), "NewStartTime", newStartTime, 20);
1268   char newStopTime[20];   int mgv17 = mg_get_var(postData, strlen(postData), "NewStopTime", newStopTime, 20);
1269   char newPriority[20];   int mgv18 = mg_get_var(postData, strlen(postData), "NewPriority", newPriority, 20);
1270   char newLifetime[20];   int mgv19 = mg_get_var(postData, strlen(postData), "NewLifetime", newLifetime, 20);
1271
1272   if ( (mgv11 == -1) || (mgv12 == -1) || (mgv13 == -1) || (mgv14 == -1) || (mgv15 == -1) || (mgv16 == -1) || (mgv17 == -1) || (mgv18 == -1) || (mgv19 == -1))
1273   {
1274     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i %i %i %i %i", mgv11, mgv12, mgv13, mgv14, mgv15, mgv16, mgv17, mgv18, mgv19);
1275     js["Result"] = false;
1276     js["Error"] = "Bad request parameters";
1277     return true;
1278   }
1279
1280   log->log("JSONServer", Log::DEBUG, "timeredit: %s %s %s %s %s %s %s %s %s", newName, newActive, newChannelID, newDay, newWeekDays, newStartTime, newStopTime, newPriority, newLifetime);
1281
1282
1283   cTimer* timer = jsonserver_findTimer2(oldName, oldActive, oldChannelID, oldDay, oldWeekDays, oldStartTime, oldStopTime, oldPriority, oldLifetime);
1284   if (!timer)
1285   {
1286     js["Result"] = false;
1287     js["Error"] = "Timer not found";
1288     return true;
1289   }
1290
1291   // Old version commented below used to set each thing individually based on whether it had changed. However, since
1292   // the only way to change the timer channel appears to be with the cTimer::Parse function, might as well use that
1293   // for everything it supports
1294   // Except flags. Get current flags, set using Parse, then add/remove active as needed the other way.
1295
1296   time_t nstt = atoi(newStartTime);
1297   struct tm nstm;
1298   localtime_r(&nstt, &nstm);
1299   int nssf = (nstm.tm_hour * 100) + nstm.tm_min;
1300
1301   time_t nztt = atoi(newStopTime);
1302   struct tm nztm;
1303   localtime_r(&nztt, &nztm);
1304   int nzsf = (nztm.tm_hour * 100) + nztm.tm_min;
1305
1306   strreplace(newName, ':', '|');
1307
1308   cString parseBuffer = cString::sprintf("%u:%s:%s:%04d:%04d:%d:%d:%s:%s",
1309                           timer->Flags(), newChannelID, *(cTimer::PrintDay(atoi(newDay), atoi(newWeekDays), true)),
1310                           nssf, nzsf, atoi(newPriority), atoi(newLifetime), newName, timer->Aux() ? timer->Aux() : "");
1311
1312   log->log("JSONServer", Log::DEBUG, "timeredit new parse: %s", *parseBuffer);
1313
1314   bool parseResult = timer->Parse(*parseBuffer);
1315   if (!parseResult)
1316   {
1317     js["Result"] = false;
1318     js["Error"] = "Timer parsing failed";
1319     return true;
1320   }
1321
1322   if (timer->HasFlags(tfActive) != !(strcasecmp(newActive, "true")))
1323   {
1324     log->log("JSONServer", Log::DEBUG, "%i %i timeredit set new active: %s", timer->HasFlags(tfActive), !(strcasecmp(newActive, "true")), newActive);
1325
1326     if (strcasecmp(newActive, "true") == 0)
1327     {
1328       timer->SetFlags(tfActive);
1329     }
1330     else if (strcasecmp(newActive, "false") == 0)
1331     {
1332       timer->ClrFlags(tfActive);
1333     }
1334     else
1335     {
1336       js["Result"] = false;
1337       js["Error"] = "Bad request parameters";
1338       return true;
1339     }
1340   }
1341
1342   js["Result"] = true;
1343   Timers.SetModified();
1344   return true;
1345
1346   /*
1347
1348   if (strcmp(timer->File(), newName))
1349   {
1350     log->log("JSONServer", Log::DEBUG, "timeredit set new name: %s", newName);
1351     timer->SetFile(newName);
1352   }
1353
1354   if (timer->Day() != atoi(newDay))
1355   {
1356     log->log("JSONServer", Log::DEBUG, "timeredit set new day: %s", newDay);
1357     timer->SetDay(atoi(newDay));
1358   }
1359
1360   if (timer->WeekDays() != atoi(newWeekDays))
1361   {
1362     log->log("JSONServer", Log::DEBUG, "timeredit set new week days: %s", newWeekDays);
1363     timer->SetWeekDays(atoi(newWeekDays));
1364   }
1365
1366   if (timer->StartTime() != atoi(newStartTime))
1367   {
1368     log->log("JSONServer", Log::DEBUG, "timeredit set new start time: %s", newStartTime);
1369     time_t nstt = atoi(newStartTime);
1370     struct tm nstm;
1371     localtime_r(&nstt, &nstm);
1372     int nssf = (nstm.tm_hour * 100) + nstm.tm_min;
1373     timer->SetStart(nssf);
1374   }
1375
1376   if (timer->StopTime() != atoi(newStopTime))
1377   {
1378     log->log("JSONServer", Log::DEBUG, "timeredit set new stop time: %s", newStopTime);
1379     time_t nztt = atoi(newStopTime);
1380     struct tm nztm;
1381     localtime_r(&nztt, &nztm);
1382     int nzsf = (nztm.tm_hour * 100) + nztm.tm_min;
1383     timer->SetStop(nzsf);
1384   }
1385
1386   if (timer->Priority() != atoi(newPriority))
1387   {
1388     log->log("JSONServer", Log::DEBUG, "timeredit set new priority: %s", newPriority);
1389     timer->SetPriority(atoi(newPriority));
1390   }
1391
1392   if (timer->Lifetime() != atoi(newLifetime))
1393   {
1394     log->log("JSONServer", Log::DEBUG, "timeredit set new lifetime: %s", newLifetime);
1395     timer->SetLifetime(atoi(newLifetime));
1396   }
1397 */
1398 }
1399
1400 cTimer* jsonserver_findTimer2(const char* rName, const char* rActive, const char* rChannelID, const char* rDay, const char* rWeekDays, const char* rStartTime, const char* rStopTime, const char* rPriority, const char* rLifetime)
1401 {
1402   Log* log = Log::getInstance();
1403   
1404   int numTimers = Timers.Count();
1405   cTimer* timer;
1406   log->log("JSONServer", Log::DEBUG, "findtimer2: %s %s %s %s %s %s %s %s %s", rName, rActive, rChannelID, rDay, rWeekDays, rStartTime, rStopTime, rPriority, rLifetime);
1407   for (int i = 0; i < numTimers; i++)
1408   {
1409     timer = Timers.Get(i);
1410
1411     log->log("JSONServer", Log::DEBUG, "findtimer2 search: %s %i %s %i %i %i %i %i %i", timer->File(), timer->HasFlags(tfActive), (const char*)timer->Channel()->GetChannelID().ToString(),
1412                                                                                         (int)timer->Day(), timer->WeekDays(), (int)timer->StartTime(), (int)timer->StopTime(),
1413                                                                                         timer->Priority(), timer->Lifetime());
1414
1415     if (    (strcmp(timer->File(), rName) == 0)
1416          && (timer->HasFlags(tfActive) == !(strcasecmp(rActive, "true")))
1417          && (strcmp(timer->Channel()->GetChannelID().ToString(), rChannelID) == 0)
1418          && (timer->Day() == atoi(rDay))
1419          && (timer->WeekDays() == atoi(rWeekDays))
1420          && (timer->StartTime() == atoi(rStartTime))
1421          && (timer->StopTime() == atoi(rStopTime))
1422          && (timer->Priority() == atoi(rPriority))
1423          && (timer->Lifetime() == atoi(rLifetime))
1424        )
1425     {
1426       log->log("JSONServer", Log::DEBUG, "found");
1427       return timer;
1428     }
1429   }
1430   log->log("JSONServer", Log::DEBUG, "no timer found");
1431   return NULL;
1432 }
1433
1434 cTimer* jsonserver_findTimer(const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays)
1435 {
1436   Log* log = Log::getInstance();
1437
1438   int numTimers = Timers.Count();
1439   cTimer* timer;
1440   for (int i = 0; i < numTimers; i++)
1441   {
1442     timer = Timers.Get(i);
1443
1444     log->log("JSONServer", Log::DEBUG, "findtimer current: %s", (const char*)timer->ToText(true));
1445     log->log("JSONServer", Log::DEBUG, "findtimer: %s", (const char*)timer->Channel()->GetChannelID().ToString());
1446     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rChannelID);
1447     log->log("JSONServer", Log::DEBUG, "findtimer: %s", timer->File());
1448     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rName);
1449     log->log("JSONServer", Log::DEBUG, "findtimer: %i", timer->StartTime());
1450     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rStartTime);
1451     log->log("JSONServer", Log::DEBUG, "findtimer: %i", timer->StopTime());
1452     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rStopTime);
1453     log->log("JSONServer", Log::DEBUG, "findtimer: %i", timer->WeekDays());
1454     log->log("JSONServer", Log::DEBUG, "findtimer: %s", rWeekDays);
1455
1456     if (
1457             (strcmp(timer->Channel()->GetChannelID().ToString(), rChannelID) == 0)
1458          && (strcmp(timer->File(), rName) == 0)
1459          && (timer->StartTime() == atoi(rStartTime))
1460          && (timer->StopTime() == atoi(rStopTime))
1461          && (timer->WeekDays() == atoi(rWeekDays))
1462        )
1463     {
1464       log->log("JSONServer", Log::DEBUG, "found");
1465       return timer;
1466     }
1467   }
1468   log->log("JSONServer", Log::DEBUG, "no timer found");
1469   return NULL;
1470 }
1471
1472 bool jsonserver_timerdel(Json::Value& js, const char* postData)
1473 {
1474   Log* log = Log::getInstance();
1475   log->log("JSONServer", Log::DEBUG, "timerdel");
1476   
1477   char rChannelID[50];  int mgv1 = mg_get_var(postData, strlen(postData), "ChannelID", rChannelID, 50);
1478   char rName[1024];  int mgv2 = mg_get_var(postData, strlen(postData), "Name", rName, 1024);
1479   char rStartTime[20];  int mgv3 = mg_get_var(postData, strlen(postData), "StartTime", rStartTime, 20);
1480   char rStopTime[20];  int mgv4 = mg_get_var(postData, strlen(postData), "StopTime", rStopTime, 20);
1481   char rWeekDays[50];  int mgv5 = mg_get_var(postData, strlen(postData), "WeekDays", rWeekDays, 20);
1482   
1483   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1))
1484   {
1485     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
1486     js["Result"] = false;
1487     js["Error"] = "Bad request parameters";
1488     return true;
1489   }
1490   
1491   log->log("JSONServer", Log::DEBUG, "timerdel: %s:%s:%s:%s:%s", rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1492   
1493   if (Timers.BeingEdited())
1494   {
1495     log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1496     js["Result"] = false;
1497     js["Error"] = "Timers being edited at VDR";
1498     return true;
1499   }
1500
1501   cTimer* timer = jsonserver_findTimer(rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1502   if (timer)
1503   {
1504     if (timer->Recording())
1505     {
1506       log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
1507       js["Result"] = false;
1508       js["Error"] = "Timer is running";
1509       return true;
1510     }
1511
1512     // delete
1513
1514     Timers.Del(timer);
1515     Timers.SetModified();
1516     js["Result"] = true;
1517     return true;
1518   }
1519   
1520   js["Result"] = false;
1521   js["Error"] = "Timer not found";
1522   return true;
1523 }
1524
1525 bool jsonserver_timerisrecording(Json::Value& js, const char* postData)
1526 {
1527   Log* log = Log::getInstance();
1528   log->log("JSONServer", Log::DEBUG, "timerisrecording");
1529
1530   char rChannelID[50];  int mgv1 = mg_get_var(postData, strlen(postData), "ChannelID", rChannelID, 50);
1531   char rName[1024];  int mgv2 = mg_get_var(postData, strlen(postData), "Name", rName, 1024);
1532   char rStartTime[20];  int mgv3 = mg_get_var(postData, strlen(postData), "StartTime", rStartTime, 20);
1533   char rStopTime[20];  int mgv4 = mg_get_var(postData, strlen(postData), "StopTime", rStopTime, 20);
1534   char rWeekDays[50];  int mgv5 = mg_get_var(postData, strlen(postData), "WeekDays", rWeekDays, 20);
1535
1536   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1))
1537   {
1538     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
1539     js["Result"] = false;
1540     js["Error"] = "Bad request parameters";
1541     return true;
1542   }
1543   
1544   log->log("JSONServer", Log::DEBUG, "timerisrecording: %s:%s:%s:%s:%s", rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1545   
1546   cTimer* timer = jsonserver_findTimer(rChannelID, rName, rStartTime, rStopTime, rWeekDays);
1547   if (timer)
1548   {
1549     js["Recording"] = timer->Recording();
1550     js["Pending"] = timer->Pending();
1551     js["Result"] = true;
1552     return true;
1553   }
1554   
1555   js["Result"] = false;
1556   js["Error"] = "Timer not found";
1557   return true;
1558 }
1559
1560 bool jsonserver_tunersstatus(Json::Value& js, const char* postData)
1561 {
1562   Log* log = Log::getInstance();
1563   log->log("JSONServer", Log::DEBUG, "tunerstatus");
1564   
1565   js["NumDevices"] = cDevice::NumDevices();
1566
1567   Json::Value jsdevices(Json::arrayValue);
1568   
1569   for (int i = 0; i < cDevice::NumDevices(); i++)
1570   {
1571     Json::Value oneDevice;
1572     cDevice *d = cDevice::GetDevice(i);
1573     oneDevice["Number"] = d->DeviceNumber();
1574     oneDevice["Type"] = (const char*)d->DeviceType();
1575     oneDevice["Name"] = (const char*)d->DeviceName();
1576     oneDevice["IsPrimary"] = d->IsPrimaryDevice();
1577
1578     const cChannel* cchannel = d->GetCurrentlyTunedTransponder();
1579     if (cchannel)
1580     {
1581       oneDevice["Frequency"] = cchannel->Frequency();
1582       oneDevice["SignalStrength"] = d->SignalStrength();
1583       oneDevice["SignalQuality"] = d->SignalQuality();
1584
1585     }
1586     else
1587     {
1588       oneDevice["Frequency"] = 0;
1589       oneDevice["SignalStrength"] = 0;
1590       oneDevice["SignalQuality"] = 0;
1591     }
1592     
1593     jsdevices.append(oneDevice);
1594   }
1595   
1596   js["Devices"] = jsdevices;
1597
1598
1599   Json::Value jstimers(Json::arrayValue);
1600   int numTimers = Timers.Count();
1601   cTimer* timer;
1602   for (int i = 0; i < numTimers; i++)
1603   {
1604     timer = Timers.Get(i);
1605
1606     if (timer->Recording())
1607     {
1608       Json::Value oneTimer;
1609       oneTimer["Recording"] = timer->Recording();
1610       oneTimer["StartTime"] = (int)timer->StartTime();
1611       oneTimer["StopTime"] = (int)timer->StopTime();
1612       oneTimer["File"] = timer->File();
1613
1614       cRecordControl* crc = cRecordControls::GetRecordControl(timer);
1615       if (crc)
1616       {
1617         cDevice* crcd = crc->Device();
1618         oneTimer["DeviceNumber"] = crcd->DeviceNumber();
1619       }
1620       else
1621       {
1622         oneTimer["DeviceNumber"] = Json::Value::null;
1623       }
1624
1625       const cChannel* channel = timer->Channel();
1626       if (channel)
1627       {
1628         oneTimer["ChannelName"] = channel->Name();
1629       }
1630       else
1631       {
1632         oneTimer["ChannelName"] = Json::Value::null;
1633       }
1634
1635       jstimers.append(oneTimer);
1636     }
1637       
1638   }
1639   js["CurrentRecordings"] = jstimers;
1640
1641   
1642   js["Result"] = true;
1643   return true;
1644 }
1645
1646
1647 bool jsonserver_epgsearchsame(Json::Value& js, const char* postData)
1648 {
1649   Log* log = Log::getInstance();
1650   log->log("JSONServer", Log::DEBUG, "epgsearchsame");
1651
1652   char sAtTime[15];  int mgv1 = mg_get_var(postData, strlen(postData), "time", sAtTime, 15);
1653   char sTitle[1024]; int mgv2 = mg_get_var(postData, strlen(postData), "title", sTitle, 1024);
1654
1655   if ( (mgv1 == -1) || (mgv2 == -1) )
1656   {
1657     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
1658     js["Result"] = false;
1659     js["Error"] = "Bad request parameters";
1660     return true;
1661   }
1662
1663   int atTime = atoi(sAtTime);
1664   log->log("JSONServer", Log::DEBUG, "request time: %i, title: %s", atTime, sTitle);
1665
1666
1667
1668   cSchedulesLock SchedulesLock;
1669   const cSchedules *schedules = cSchedules::Schedules(SchedulesLock);
1670   if (!schedules)
1671   {
1672     js["Result"] = false;
1673     return true;
1674   }
1675
1676   Json::Value jsevents(Json::arrayValue);
1677
1678   const cEvent *event;
1679   for (cSchedule *schedule = schedules->First(); (schedule != NULL); schedule = schedules->Next(schedule))
1680   {
1681     event = schedule->GetEventAround(atTime);
1682     if (!event) continue; // nothing found on this schedule(channel)
1683
1684     if (!strcmp(event->Title(), sTitle))
1685     {
1686       Json::Value oneEvent;
1687       oneEvent["ChannelID"] = (const char*)event->ChannelID().ToString();
1688       oneEvent["ID"] = event->EventID();
1689       oneEvent["Time"] = (Json::UInt)event->StartTime();
1690       oneEvent["Duration"] = event->Duration();
1691       oneEvent["Title"] = event->Title() ? event->Title() : "";
1692       oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
1693       oneEvent["HasTimer"] = event->HasTimer();
1694       //oneEvent["Description"] = event->Description() ? event->Description() : "";
1695       jsevents.append(oneEvent);
1696     }
1697   }
1698
1699   js["Events"] = jsevents;
1700   js["Result"] = true;
1701   return true;
1702 }
1703
1704 bool jsonserver_epgdownload(Json::Value& js, const char* postData)
1705 {
1706   Log* log = Log::getInstance();
1707   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
1708
1709   cSchedulesLock MutexLock;
1710   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1711
1712   if (!Schedules)
1713   {
1714     log->log("JSONServer", Log::ERR, "Could not get Schedules object");
1715     js["Result"] = false;
1716     js["Error"] = "Internal schedules error (1)";
1717     return true;
1718   }
1719
1720   Json::Value jsevents(Json::arrayValue);
1721
1722   for (cChannel* channel = Channels.First(); channel; channel = Channels.Next(channel))
1723   {
1724     if (channel->GroupSep()) continue;
1725
1726     const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1727     if (!Schedule) continue;
1728
1729
1730     for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1731     {
1732       Json::Value oneEvent;
1733       oneEvent["ChannelNumber"] = channel->Number();
1734       oneEvent["ChannelID"] = (const char*)event->ChannelID().ToString();
1735       oneEvent["ID"] = event->EventID();
1736       oneEvent["Time"] = (Json::UInt)event->StartTime();
1737       oneEvent["Duration"] = event->Duration();
1738       oneEvent["Title"] = event->Title() ? event->Title() : "";
1739       oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
1740       oneEvent["HasTimer"] = event->HasTimer();
1741       oneEvent["Description"] = event->Description() ? event->Description() : "";
1742       jsevents.append(oneEvent);
1743     }
1744   }
1745
1746   js["Result"] = true;
1747   js["Events"] = jsevents;
1748   return true;
1749 }