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