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