]> git.vomp.tv Git - jsonserver.git/blob - handler.c
Stop a recording timer from a recording point of view
[jsonserver.git] / handler.c
1 #include "handler.h"
2
3 #include <string.h>
4 #include <stdlib.h>
5 #include <jsoncpp/json/json.h>
6 #include <string>
7
8 #include <vdr/videodir.h>
9 #include <vdr/recording.h>
10 #include <vdr/menu.h>
11 #include <vdr/timers.h>
12
13 #include "log.h"
14
15 int jsonserver_request_handler(struct mg_connection *conn)
16 {
17   Log* log = Log::getInstance();
18   const struct mg_request_info *request_info = mg_get_request_info(conn);
19   
20   if (strcmp(request_info->uri, "/jsonserver")) return 0; // not for us
21
22   char wvrequest[20];
23   int wvrl = mg_get_var(request_info->query_string, strlen(request_info->query_string), "req", wvrequest, 20);
24   if (wvrl == -1)
25   {
26     log->log("JSONServer", Log::ERR, "Could not decode req");
27     return 0;
28   }
29
30 /*
31   if (!strcmp(request_info->request_method, "OPTIONS"))
32   {
33     mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
34     mg_printf(conn, "%s", "Access-Control-Allow-Origin: *\r\n");
35     mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
36     return (void*)1;
37   }
38 */
39
40   // Get POST data
41   char postData[10000];
42   postData[0] = '\0';
43   if (!strcmp(request_info->request_method, "POST"))
44   {
45     const char* contentLength = mg_get_header(conn, "Content-Length");
46     int contentLengthI = atoi(contentLength);
47     log->log("JSONServer", Log::DEBUG, "POST data content length: %i", contentLengthI);
48     if (contentLengthI > 10000)
49     {
50       log->log("JSONServer", Log::DEBUG, "Length > 10000, rejecting");
51       return 0;
52     }
53
54     if (contentLengthI > 0)
55     {
56       // FIXME - assume for now that all post data will be small enough to have arrived immediately
57       int bytesRead = mg_read(conn, postData, contentLengthI);
58       if (bytesRead != contentLengthI)
59       {
60         log->log("JSONServer", Log::DEBUG, "Could not read up to contentLength");
61         return 0;
62       }
63       postData[contentLengthI] = '\0';
64     }
65   }
66
67   Json::Value js;
68   bool success = false;
69
70   if      (!strcmp(wvrequest, "reclist")) success = jsonserver_reclist(js);
71   else if (!strcmp(wvrequest, "recinfo")) success = jsonserver_recinfo(js, postData);
72   else if (!strcmp(wvrequest, "recdel")) success = jsonserver_recdel(js, postData);
73   else if (!strcmp(wvrequest, "recmove")) success = jsonserver_recmove(js, postData);
74   else if (!strcmp(wvrequest, "recstop")) success = jsonserver_recstop(js, postData);
75   else if (!strcmp(wvrequest, "channellist")) success = jsonserver_channellist(js);
76   else if (!strcmp(wvrequest, "channelschedule")) success = jsonserver_channelschedule(js, postData);
77   else if (!strcmp(wvrequest, "timerlist")) success = jsonserver_timerlist(js);
78   else if (!strcmp(wvrequest, "timerdel")) success = jsonserver_timerdel(js, postData);
79   else if (!strcmp(wvrequest, "timerset")) success = jsonserver_timerset(js, postData);
80
81   if (!success) return 0; // the specific handler failed badly
82
83   // Now js will be filled
84
85   Json::StyledWriter sw;
86   std::string jsonout = sw.write(js);
87   mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
88   mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
89   mg_write(conn, jsonout.c_str(), jsonout.length());
90   return 1;
91
92   
93 /*
94   else if (event == MG_EVENT_LOG)
95   {
96     if (request_info->status_code == 400) // bad request
97     {
98       log->log("Mongoose", Log::DEBUG, "400 BAD REQUEST:");
99       log->log("Mongoose", Log::DEBUG, request_info->request_method);
100       log->log("Mongoose", Log::DEBUG, request_info->uri);
101       log->log("Mongoose", Log::DEBUG, request_info->http_version);
102       log->log("Mongoose", Log::DEBUG, request_info->query_string);
103       log->log("Mongoose", Log::DEBUG, request_info->log_message);
104       for (int i = 0; i < request_info->num_headers; i++)
105       {
106         log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
107       }
108     }
109     else
110     {
111       log->log("Mongoose", Log::DEBUG, request_info->log_message);
112       log->log("Mongoose", Log::DEBUG, request_info->uri);
113     }
114     return (void*)1;
115   }
116   
117   // other events not handled:
118   // MG_HTTP_ERROR, MG_INIT_SSL
119   // Let mongoose do something with those
120
121   return NULL;
122
123 */
124   
125 }
126
127 bool jsonserver_reclist(Json::Value& js)
128 {
129   Log* log = Log::getInstance();
130   log->log("JSONServer", Log::DEBUG, "reclist");
131
132   int FreeMB;
133   int Percent = VideoDiskSpace(&FreeMB);
134   int Total = (FreeMB / (100 - Percent)) * 100;
135         
136   js["MBFree"] = FreeMB;
137   js["Percent"] = Percent;
138   js["Total"] = Total;
139   
140   Json::Value jsrecordings;
141   cRecordings Recordings;
142   Recordings.Load();
143   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
144   {
145     Json::Value oneRec;
146     oneRec["StartTime"] = (Json::UInt)recording->Start();
147     oneRec["Length"] = (Json::UInt)recording->LengthInSeconds();
148     oneRec["IsNew"] = recording->IsNew();
149     oneRec["Name"] = recording->Name();
150     oneRec["Filename"] = recording->FileName();
151     jsrecordings.append(oneRec);
152   }
153   js["Recordings"] = jsrecordings;
154   
155   return true;
156 }
157
158 bool jsonserver_recinfo(Json::Value& js, const char* postData)
159 {
160   Log* log = Log::getInstance();
161   log->log("JSONServer", Log::DEBUG, "recinfo");
162
163   char reqfilename[1000];
164   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
165   if (mgv1 == -1)
166   {
167     log->log("JSONServer", Log::ERR, "Could not decode filename");
168     js["Result"] = false;
169     js["Error"] = "Could not decode filename";
170     return true;
171   }
172
173   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
174   
175   cRecordings Recordings;
176   Recordings.Load(); // probably have to do this
177   cRecording *recording = Recordings.GetByName(reqfilename);
178
179   if (!recording)
180   {
181     log->log("JSONServer", Log::ERR, "recinfo found no recording");
182     js["Result"] = false;
183     return true;
184   }
185
186   js["IsNew"] = recording->IsNew();
187   js["LengthInSeconds"] = recording->LengthInSeconds();
188   js["FileSizeMB"] = recording->FileSizeMB();
189   js["Name"] = recording->Name() ? recording->Name() : Json::Value::null;
190   js["Priority"] = recording->Priority();
191   js["LifeTime"] = recording->Lifetime();
192   js["Start"] = (Json::UInt)recording->Start();
193
194   js["ResumePoint"] = 0;
195   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
196   if (ResumeFile.Read() >= 0) js["ResumePoint"] = ResumeFile.Read();
197
198   js["CurrentlyRecordingStart"] = 0;
199   js["CurrentlyRecordingStop"] = 0;
200   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
201   if (rc)
202   {
203     js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
204     js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
205   }
206
207   const cRecordingInfo *info = recording->Info();
208   if (info)
209   {
210     js["ChannelName"] = info->ChannelName() ? info->ChannelName() : Json::Value::null;
211     js["Title"] = info->Title() ? info->Title() : Json::Value::null;
212     js["ShortText"] = info->ShortText() ? info->ShortText() : Json::Value::null;
213     js["Description"] = info->Description() ? info->Description() : Json::Value::null;
214
215     const cComponents* components = info->Components();
216     if (!components)
217     {
218       js["Components"] = Json::Value::null;
219     }
220     else
221     {
222       Json::Value jscomponents;
223
224       tComponent* component;
225       for (int i = 0; i < components->NumComponents(); i++)
226       {
227         component = components->Component(i);
228
229         Json::Value oneComponent;
230         oneComponent["Stream"] = component->stream;
231         oneComponent["Type"] = component->type;
232         oneComponent["Language"] = component->language ? component->language : Json::Value::null;
233         oneComponent["Description"] = component->description ? component->description : Json::Value::null;
234         jscomponents.append(oneComponent);
235       }
236
237       js["Components"] = jscomponents;
238     }
239   }
240
241   js["Result"] = true;
242   return true;
243 }
244
245 bool jsonserver_recstop(Json::Value& js, const char* postData)
246 {
247   Log* log = Log::getInstance();
248   log->log("JSONServer", Log::DEBUG, "recstop");
249   
250   char reqfilename[1000];
251   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
252   if (mgv1 == -1)
253   {
254     log->log("JSONServer", Log::ERR, "Could not decode filename");
255     js["Result"] = false;
256     js["Error"] = "Could not decode filename";
257     return true;
258   }
259   
260   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
261   
262   cRecordings Recordings;
263   Recordings.Load(); // probably have to do this
264   cRecording *recording = Recordings.GetByName(reqfilename);
265   
266   if (!recording)
267   {
268     log->log("JSONServer", Log::ERR, "recstop found no recording");
269     js["Result"] = false;
270     return true;
271   }
272
273   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
274   if (!rc)
275   {
276     log->log("JSONServer", Log::ERR, "recstop - not currently recording");
277     js["Result"] = false;
278     return true;
279   }
280
281   if (Timers.BeingEdited())
282   {
283     log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
284     js["Result"] = false;
285     return true;
286   }
287
288   cTimer* timer = rc->Timer();
289   if (!timer)
290   {
291     log->log("JSONServer", Log::ERR, "recstop - timer not found");
292     js["Result"] = false;
293     return true;
294   }
295   
296   timer->ClrFlags(tfActive);
297   Timers.SetModified();
298   
299   js["Result"] = true;
300   return true;
301 }  
302   
303 bool jsonserver_recdel(Json::Value& js, const char* postData)
304 {
305   Log* log = Log::getInstance();
306   log->log("JSONServer", Log::DEBUG, "recdel");
307
308   char reqfilename[1000];
309   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
310   if (mgv1 == -1)
311   {
312     log->log("JSONServer", Log::ERR, "Could not decode filename");
313     js["Result"] = false;
314     js["Error"] = "Could not decode filename";
315     return true;
316   }
317
318   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
319   
320   cRecordings Recordings;
321   Recordings.Load(); // probably have to do this
322   cRecording *recording = Recordings.GetByName(reqfilename);
323
324   if (!recording)
325   {
326     js["Result"] = false;
327     js["Error"] = "Could not find recording to delete";
328     return true;
329   }
330
331   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
332   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
333   if (rc)
334   {
335     js["Result"] = false;
336     js["Error"] = "This recording is still recording.. ho ho";
337     return true;
338   }
339
340   if (recording->Delete())
341   {
342     ::Recordings.DelByName(recording->FileName());
343     js["Result"] = true;
344   }
345   else
346   {
347     js["Result"] = false;
348     js["Error"] = "Failed to delete recording";
349   }
350
351   return true;
352 }
353
354 bool jsonserver_recmove(Json::Value& js, const char* postData)
355 {
356   Log* log = Log::getInstance();
357   log->log("JSONServer", Log::DEBUG, "recmove");
358
359   char sFileName[1000]; int mgv1 = mg_get_var(postData, strlen(postData), "filename", sFileName, 1000);  
360   char sNewPath[1000];  int mgv2 = mg_get_var(postData, strlen(postData), "newpath", sNewPath, 1000);  
361
362   if ( (mgv1 == -1) || (mgv2 == -1) || !strlen(sFileName) || !strlen(sNewPath) )
363   {
364     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
365     js["Result"] = false;
366     js["Error"] = "Bad request parameters";
367     return true;
368   }
369
370   cRecordings Recordings;
371   Recordings.Load(); // probably have to do this
372   cRecording* recording = Recordings.GetByName(sFileName);
373
374   if (!recording)
375   {
376     log->log("JSONServer", Log::ERR, "Could not find recording to move");
377     js["Result"] = false;
378     js["Error"] = "Bad filename";
379     return true;
380   }
381
382   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
383   if (rc)
384   {
385     log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
386     js["Result"] = false;
387     js["Error"] = "Cannot move recording in progress";
388     return true;
389   }
390   
391   log->log("JSONServer", Log::DEBUG, "moving recording: %s", recording->Name());
392   log->log("JSONServer", Log::DEBUG, "moving recording: %s", recording->FileName());
393   log->log("JSONServer", Log::DEBUG, "to: %s", sNewPath);
394
395   const char* t = recording->FileName();
396
397   char* dateDirName = NULL;   int k;
398   char* titleDirName = NULL;  int j;
399   char* newContainer = NULL;
400
401   // Find the datedirname
402   for(k = strlen(t) - 1; k >= 0; k--)
403   {
404     if (t[k] == '/')
405     {
406       log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
407       dateDirName = new char[strlen(&t[k+1]) + 1];
408       strcpy(dateDirName, &t[k+1]);
409       break;
410     }
411   }
412
413   // Find the titledirname
414
415   for(j = k-1; j >= 0; j--)
416   {
417     if (t[j] == '/')
418     {
419       log->log("JSONServer", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
420       titleDirName = new char[(k - j - 1) + 1];
421       memcpy(titleDirName, &t[j+1], k - j - 1);
422       titleDirName[k - j - 1] = '\0';
423       break;
424     }
425   }
426
427   log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
428   log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
429   log->log("JSONServer", Log::DEBUG, "viddir: %s", VideoDirectory);
430
431   ExchangeChars(sNewPath, true);
432   log->log("JSONServer", Log::DEBUG, "EC: %s", sNewPath);
433
434   newContainer = new char[strlen(VideoDirectory) + strlen(sNewPath) + strlen(titleDirName) + 1];
435   log->log("JSONServer", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(sNewPath) + strlen(titleDirName) + 1);
436   sprintf(newContainer, "%s%s%s", VideoDirectory, sNewPath, titleDirName);
437   log->log("JSONServer", Log::DEBUG, "%s", newContainer);
438
439   struct stat dstat;
440   int statret = stat(newContainer, &dstat);
441   if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
442   {
443     log->log("JSONServer", Log::DEBUG, "new dir does not exist");
444     int mkdirret = mkdir(newContainer, 0755);
445     if (mkdirret != 0)
446     {
447       delete[] dateDirName;
448       delete[] titleDirName;
449       delete[] newContainer;
450
451       log->log("JSONServer", Log::ERR, "Failed to make new dir");
452       js["Result"] = false;
453       js["Error"] = "Failed to create new directory";
454       return true;
455     }
456   }
457   else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
458   {
459     delete[] dateDirName;
460     delete[] titleDirName;
461     delete[] newContainer;
462
463     log->log("JSONServer", Log::ERR, "Something already exists?");
464     js["Result"] = false;
465     js["Error"] = "Something already exists at the new path";
466     return true;
467   }
468
469   // Ok, the directory container has been made, or it pre-existed.
470
471   char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
472   sprintf(newDir, "%s/%s", newContainer, dateDirName);
473
474   log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
475   int renameret = rename(t, newDir);
476   if (renameret == 0)
477   {
478     // Success. Test for remove old dir containter
479     char* oldTitleDir = new char[k+1];
480     memcpy(oldTitleDir, t, k);
481     oldTitleDir[k] = '\0';
482     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
483     rmdir(oldTitleDir); // can't do anything about a fail result at this point.
484     delete[] oldTitleDir;
485
486     ::Recordings.Update();
487     js["Result"] = true;
488     js["NewRecordingFileName"] = newDir;
489   }
490   else
491   {
492     log->log("JSONServer", Log::ERR, "Rename failed");
493     js["Result"] = false;
494     js["Error"] = "Move failed";
495   }
496
497   delete[] dateDirName;
498   delete[] titleDirName;
499   delete[] newContainer;
500   delete[] newDir;
501
502   return true;
503 }
504
505 bool jsonserver_channellist(Json::Value& js)
506 {
507   Log* log = Log::getInstance();
508   log->log("JSONServer", Log::DEBUG, "channellist");
509
510   Json::Value jschannels;
511   
512   int type;
513   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
514   {
515     if (!channel->GroupSep())
516     {
517       log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
518
519       if (channel->Vpid()) type = 1;
520       else if (channel->Apid(0)) type = 2;
521       else continue;
522
523       Json::Value oneChannel;
524       oneChannel["Number"] = channel->Number();
525       oneChannel["Type"] = type;
526       oneChannel["Name"] = channel->Name();
527 #if VDRVERSNUM < 10703
528       oneChannel["VType"] = 2;
529 #else
530       oneChannel["VType"] = channel->Vtype();
531 #endif
532       jschannels.append(oneChannel);    
533     }
534   }
535   js["Channels"] = jschannels;
536   
537   return true;
538 }
539
540 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
541 {
542   Log* log = Log::getInstance();
543   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
544
545   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);  
546   char sStartTime[15];      int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);  
547   char sDuration[15];       int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);  
548
549   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
550   {
551     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
552     js["Result"] = false;
553     js["Error"] = "Bad request parameters";
554     return true;
555   }
556
557   int channelNumber = atoi(sChannelNumber);
558   int startTime = atoi(sStartTime); 
559   int duration = atoi(sDuration); 
560
561   cChannel* channel = NULL;
562   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
563   {
564     if (channel->GroupSep()) continue;
565     if (channel->Number() == channelNumber) break;
566   }
567
568   if (!channel)
569   {
570     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
571     js["Result"] = false;
572     js["Error"] = "Could not find channel";
573     return true;
574   }
575
576   cSchedulesLock MutexLock;
577   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
578   if (!Schedules)
579   {
580     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
581     js["Result"] = false;
582     js["Error"] = "Internal schedules error (1)";
583     return true;
584   }
585   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
586   if (!Schedule)     
587   {
588     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
589     js["Result"] = false;
590     js["Error"] = "Internal schedules error (2)";
591     return true;
592   }
593     
594   Json::Value jsevents;
595
596   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
597   {
598     //in the past filter
599     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
600    //start time filter
601     if ((event->StartTime() + event->Duration()) <= startTime) continue;
602     //duration filter
603     if (event->StartTime() >= (startTime + duration)) continue;
604
605     Json::Value oneEvent;
606     oneEvent["ID"] = event->EventID();
607     oneEvent["Time"] = (Json::UInt)event->StartTime();
608     oneEvent["Duration"] = event->Duration();
609     oneEvent["Title"] = event->Title() ? event->Title() : "";
610     oneEvent["Description"] = event->Description() ? event->Description() : "";
611     jsevents.append(oneEvent);
612   }
613
614   js["Events"] = jsevents;
615   return true;
616 }
617
618 bool jsonserver_timerlist(Json::Value& js)
619 {
620   Log* log = Log::getInstance();
621   log->log("JSONServer", Log::DEBUG, "timerlist");
622
623   Json::Value jstimers;
624   
625   cTimer *timer;
626   int numTimers = Timers.Count();
627
628   for (int i = 0; i < numTimers; i++)
629   {
630     timer = Timers.Get(i);
631     Json::Value oneTimer;
632     oneTimer["Active"] = timer->HasFlags(tfActive);
633     oneTimer["Recording"] = timer->Recording();
634     oneTimer["Pending"] = timer->Pending();
635     oneTimer["Priority"] = timer->Priority();
636     oneTimer["Lifetime"] = timer->Lifetime();
637     oneTimer["ChannelNumber"] = timer->Channel()->Number();
638     oneTimer["StartTime"] = (int)timer->StartTime();
639     oneTimer["StopTime"] = (int)timer->StopTime();
640     oneTimer["Day"] = (int)timer->Day();
641     oneTimer["WeekDays"] = timer->WeekDays();
642     oneTimer["Name"] = timer->File();
643     jstimers.append(oneTimer);
644   }
645   
646   js["Timers"] = jstimers;
647   return true;
648 }
649
650 bool jsonserver_timerdel(Json::Value& js, const char* postData)
651 {
652   Log* log = Log::getInstance();
653   log->log("JSONServer", Log::DEBUG, "timerdel");
654
655   char sdelChannel[15];   int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);  
656   char sdelWeekdays[15];  int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);  
657   char sdelDay[15];       int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);  
658   char sdelStart[15];     int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);  
659   char sdelStop[15];      int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);  
660
661   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
662   {
663     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
664     js["Result"] = false;
665     js["Error"] = "Bad request parameters";
666     return true;
667   }
668
669   int delChannel = atoi(sdelChannel); 
670   int delWeekdays = atoi(sdelWeekdays); 
671   int delDay = atoi(sdelDay); 
672   int delStart = atoi(sdelStart); 
673   int delStop = atoi(sdelStop); 
674
675   cTimer* ti = NULL;
676   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
677   {
678     if  ( (ti->Channel()->Number() == delChannel)
679      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
680      &&   (ti->StartTime() == delStart)
681      &&   (ti->StopTime() == delStop) )
682        break;
683   }
684   
685   if (!ti)
686   {
687     log->log("JSONServer", Log::ERR, "Could not find timer");
688     js["Result"] = false;
689     js["Error"] = "Could not find timer";
690     return true;
691   }
692
693   if (Timers.BeingEdited())
694   {
695     log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
696     js["Result"] = false;
697     js["Error"] = "Timers being edited at VDR";
698     return true; 
699   }
700   
701   if (ti->Recording())
702   {
703     log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
704     js["Result"] = false;
705     js["Error"] = "Timer is running";
706     return true;
707   }
708   
709   Timers.Del(ti);
710   Timers.SetModified();
711   js["Result"] = true;
712     
713   return true;
714 }
715
716 bool jsonserver_timerset(Json::Value& js, const char* postData)
717 {
718   Log* log = Log::getInstance();
719   log->log("JSONServer", Log::DEBUG, "timerset");
720
721   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
722
723   if (mgv1 == -1)
724   {
725     log->log("JSONServer", Log::ERR, "Could not get timerstring");
726     js["Result"] = false;
727     js["Error"] = "Bad request parameters";
728     return true;
729   }
730
731   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
732   cTimer *timer = new cTimer;
733   if (!timer->Parse(sTimerString))
734   {
735     delete timer;
736     js["Result"] = false;
737     js["Error"] = "Failed to parse timer request details";
738     return true;
739   }
740
741   cTimer *t = Timers.GetTimer(timer);
742   if (t)
743   {
744     delete timer;
745     js["Result"] = false;
746     js["Error"] = "Timer already exists";
747     return true;
748   }
749
750   Timers.Add(timer);
751   Timers.SetModified();
752   js["Result"] = true;
753   return true;
754 }
755