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