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