diff options
Diffstat (limited to 'webdo.c')
-rw-r--r-- | webdo.c | 1964 |
1 files changed, 1964 insertions, 0 deletions
@@ -0,0 +1,1964 @@ +/* + * webdo.c + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "lib/imgtools.h" +#include "lib/curl.h" + +#include "svdrpclient.h" + +#include "httpd.h" + +//*************************************************************************** +// Collect Scraper Data +//*************************************************************************** + +int cEpgHttpd::collectScraperData(json_t* oScraperData, int movieId, int seriesId, int episodeId) +{ + if (movieId) + { + movieDb->clear(); + movieDb->setValue("MOVIEID", movieId); + + if (selectMovie->find()) + { + json_t* oMovieData = json_object(); + + addFieldToJson(oMovieData, movieDb, "MovieId"); + addFieldToJson(oMovieData, movieDb, "Title"); + addFieldToJson(oMovieData, movieDb, "OriginalTitle"); + addFieldToJson(oMovieData, movieDb, "Tagline"); + addFieldToJson(oMovieData, movieDb, "Overview"); + addFieldToJson(oMovieData, movieDb, "IsAdult"); + addFieldToJson(oMovieData, movieDb, "CollectionId"); + addFieldToJson(oMovieData, movieDb, "CollectionName"); + addFieldToJson(oMovieData, movieDb, "Budget"); + addFieldToJson(oMovieData, movieDb, "Revenue"); + addFieldToJson(oMovieData, movieDb, "Genres"); + addFieldToJson(oMovieData, movieDb, "Homepage"); + addFieldToJson(oMovieData, movieDb, "ReleaaseDate"); + addFieldToJson(oMovieData, movieDb, "Runtime"); + addFieldToJson(oMovieData, movieDb, "Popularity"); + addFieldToJson(oMovieData, movieDb, "VoteAverage"); + + // movie actors and actors media + + json_t* oActorsData = json_object(); + + movieActorsDb->clear(); + movieActorDb->clear(); + movieMediaDb->clear(); + movieActorsDb->setValue("MovieId", movieId); + + for (int f = selectMovieActors->find(); f; f = selectMovieActors->fetch()) + { + json_t* oActorData = json_object(); + + addFieldToJson(oActorData, movieActorDb, "ActorId"); + addFieldToJson(oActorData, movieActorDb, "ActorName"); + addFieldToJson(oActorData, movieActorsDb, "Role"); + addFieldToJson(oActorData, movieMediaDb, "MediaType"); + // addFieldToJson(oActorData, &imageSize, yes, "media_size"); + // addFieldToJson(oActorData, movieMediaDb, "MediaUrl"); + + json_object_set_new(oActorsData, num2Str(movieactorActorId->getIntValue()).c_str(), oActorData); + } + + selectMovieActors->freeResult(); + + // movie media + + json_t* oMovieMedia = json_object(); + + movieMediaDb->clear(); + movieMediaDb->setValue("MovieId", movieId); + + for (int f = selectMovieMedia->find(); f; f = selectMovieMedia->fetch()) + json_object_set_new(oMovieMedia, num2Str(moviemediaMediaType->getIntValue()).c_str(), json_integer(1)); + + selectMovieMedia->freeResult(); + selectMovie->freeResult(); + + // concaternate + + json_object_set_new(oMovieData, "media", oMovieMedia); + json_object_set_new(oMovieData, "actors", oActorsData); + json_object_set_new(oScraperData, "movie", oMovieData); + } + } + + // series data from scraper + + if (seriesId) + { + seriesDb->clear(); + seriesDb->setValue("SeriesId", seriesId); + + if (selectSerie->find()) + { + json_t* oSeriesData = json_object(); + + addFieldToJson(oSeriesData, seriesDb, "SeriesId"); + addFieldToJson(oSeriesData, seriesDb, "SeriesName"); + addFieldToJson(oSeriesData, seriesDb, "SeriesOverview"); + addFieldToJson(oSeriesData, seriesDb, "SeriesFirstAired"); + addFieldToJson(oSeriesData, seriesDb, "SeriesNetwork"); + addFieldToJson(oSeriesData, seriesDb, "SeriesGenre"); + addFieldToJson(oSeriesData, seriesDb, "SeriesRating"); + addFieldToJson(oSeriesData, seriesDb, "SeriesStatus"); + + // series episode + + seriesEpisodeDb->clear(); + seriesEpisodeDb->setValue("EpisodeId", episodeId); + + if (selectSeriesEpisode->find()) + { + json_t* oSeriesEpisodeData = json_object(); + + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeName"); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeId"); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeNumber" ); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "SeasonNumber"); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeOverview"); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeFirstAired"); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeGuestStars"); + addFieldToJson(oSeriesEpisodeData, seriesEpisodeDb, "EpisodeRating"); + + // series/epidode media + + seriesMediaDb->clear(); + seriesMediaDb->setValue("SeriesId", seriesId); + seriesMediaDb->setValue("SeasonNumber", seriesepisodeSeasonNumber->getIntValue()); + seriesMediaDb->setValue("EpisodeId", seriesepisodeEpisodeId->getIntValue()); + + json_t* oSeriesMedias = json_object(); + json_t* oSeriesActors = json_object(); + + for (int f = selectSeriesMedia->find(); f; f = selectSeriesMedia->fetch()) + { + json_object_set_new(oSeriesMedias, num2Str(seriesmediaMediaType->getIntValue()).c_str(), json_integer(1)); + + if (seriesmediaActorId->getIntValue()) + { + json_t* oSeriesActorData = json_object(); + + addFieldToJson(oSeriesActorData, seriesActorsDb, "ActorName"); + addFieldToJson(oSeriesActorData, seriesActorsDb, "ActorRole"); + addFieldToJson(oSeriesActorData, seriesActorsDb, "SortOrder"); + + json_object_set_new(oSeriesActors, num2Str(seriesmediaActorId->getIntValue()).c_str(), oSeriesActorData); + } + } + + selectSeriesMedia->freeResult(); + selectSeriesEpisode->freeResult(); + + // concaternate + + json_object_set_new(oSeriesData, "actors", oSeriesActors); + json_object_set_new(oSeriesData, "media", oSeriesMedias); + json_object_set_new(oSeriesData, "episode", oSeriesEpisodeData); + } + + selectSerie->freeResult(); + + json_object_set_new(oScraperData, "serie", oSeriesData); + } + } + + return done; +} + +//*************************************************************************** +// Do Update Searchtimer +//*************************************************************************** + +int cEpgHttpd::doUpdateSearchtimer(MHD_Connection* tcp, json_t* obj) +{ + triggerEpgd(); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Update Recording Table +//*************************************************************************** + +int cEpgHttpd::doUpdateRecordingTable(MHD_Connection* tcp, json_t* obj) +{ + triggerVdrs("UPDR"); + triggerVdrs("UPDREC", "epg2vdr"); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Wakeup VDR +//*************************************************************************** + +int cEpgHttpd::doWakeupVdr(MHD_Connection* tcp, json_t* obj) +{ + int status = MHD_HTTP_OK; + const char* uuid = getStrParameter(tcp, "uuid"); + + if (isEmpty(uuid)) + status = MHD_HTTP_INTERNAL_SERVER_ERROR; + + if (wakeupVdr(uuid) != success) + status = MHD_HTTP_INTERNAL_SERVER_ERROR; + + return buildResponse(obj, status, status == MHD_HTTP_OK ? "done" : "wakeup failed"); +} + +//*************************************************************************** +// Do Rename Recording +//*************************************************************************** + +int cEpgHttpd::doRenameRecording(MHD_Connection* tcp, json_t* obj) +{ + int status; + int alive = no; + const char* ip = 0; + int port = 0; + const char* vdrUuid = 0; + const char* videoBasePath = ""; + char* opt; + char result[512+TB] = ""; + + const char* md5path = getStrParameter(tcp, "md5path"); + time_t starttime = getIntParameter(tcp, "starttime"); + const char* owner = getStrParameter(tcp, "owner", ""); + const char* newName = getStrParameter(tcp, "name"); + + if (isEmpty(md5path) || !starttime || isEmpty(newName)) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Missing recording reference in request"); + + recordingListDb->clear(); + recordingListDb->setValue("MD5PATH", md5path); + recordingListDb->setValue("STARTTIME", starttime); + recordingListDb->setValue("OWNER", owner); + + if (!recordingListDb->find()) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Recording '%s' not found", md5path); + + vdrUuid = recordingListDb->getStrValue("VDRUUID"); + alive = ipOfVdr(recordingListDb->getStrValue("VDRUUID"), ip, port); + + recordingListDb->reset(); + + if (!alive || isEmpty(ip) || !port) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Can't rename recording, VDR is not alive"); + + vdrDb->clear(); + vdrDb->setValue("UUID", vdrUuid); + + if (vdrDb->find()) + videoBasePath = vdrDb->getStrValue("VIDEODIR"); + + vdrDb->reset(); + + asprintf(&opt, "%s/%s %s", videoBasePath, recordingListDb->getStrValue("PATH"), newName); + status = triggerVdr(ip, port, "RENREC", "epg2vdr", opt, result); + free(opt); + + if (status != success) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "%s", result); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Delete Recording +//*************************************************************************** + +int cEpgHttpd::doDeleteRecording(MHD_Connection* tcp, json_t* obj) +{ + int status; + int alive = no; + const char* ip = 0; + int port = 0; + char* name = 0; + char result[512+TB] = ""; + const char* vdrUuid = 0; + const char* videoBasePath = ""; + + const char* md5path = getStrParameter(tcp, "md5path"); + time_t starttime = getIntParameter(tcp, "starttime"); + const char* owner = getStrParameter(tcp, "owner", ""); + + if (isEmpty(md5path) || !starttime) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Missing recording reference in request"); + + recordingListDb->clear(); + recordingListDb->setValue("MD5PATH", md5path); + recordingListDb->setValue("STARTTIME", starttime); + recordingListDb->setValue("OWNER", owner); + + if (!recordingListDb->find()) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Recording '%s' not found", md5path); + + vdrUuid = recordingListDb->getStrValue("VDRUUID"); + alive = ipOfVdr(vdrUuid, ip, port); + + recordingListDb->reset(); + + if (!alive || isEmpty(ip) || !port) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Can't delete recording, VDR is not alive"); + + vdrDb->clear(); + vdrDb->setValue("Uuid", vdrUuid); + vdrDb->reset(); + + if (vdrDb->find()) + videoBasePath = vdrDb->getStrValue("VIDEODIR"); + + vdrDb->reset(); + + asprintf(&name, "%s/%s", videoBasePath, recordingListDb->getStrValue("PATH")); + status = triggerVdr(ip, port, "DELREC", "epg2vdr", name, result); + free(name); + + if (status != success) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "%s", result); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Replay Recording +//*************************************************************************** + +int cEpgHttpd::doReplayRecording(MHD_Connection* tcp, json_t* obj) +{ + int status; + int alive = no; + const char* ip = 0; + int port = 0; + char* opt = 0; + const char* name = 0; + char result[512+TB] = ""; + const char* videoBasePath = ""; + + const char* md5path = getStrParameter(tcp, "md5path"); + const char* owner = getStrParameter(tcp, "owner", ""); + time_t starttime = getIntParameter(tcp, "starttime"); + const char* vdruuid = getStrParameter(tcp, "vdruuid"); + const char* position = getStrParameter(tcp, "position", ""); + + if (isEmpty(md5path) || isEmpty(vdruuid) || !starttime) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Missing recording or vdr reference in request"); + + if (strcasecmp(owner, "undefined") == 0) + owner = ""; + + recordingListDb->clear(); + recordingListDb->setValue("MD5PATH", md5path); + recordingListDb->setValue("STARTTIME", starttime); + recordingListDb->setValue("OWNER", owner); + + if (!recordingListDb->find()) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Recording '%s/%s/%ld' not found", md5path, owner, starttime); + + alive = ipOfVdr(vdruuid, ip, port); + name = recordingListDb->getStrValue("PATH"); + + recordingListDb->reset(); + + vdrDb->clear(); + vdrDb->setValue("Uuid", vdruuid); + vdrDb->reset(); + + if (vdrDb->find()) + videoBasePath = vdrDb->getStrValue("VIDEODIR"); + + vdrDb->reset(); + + if (!alive || isEmpty(ip) || !port) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Can't replay recording, VDR is not alive"); + + asprintf(&opt, "%s/%s %s", videoBasePath, name, position); + status = triggerVdr(ip, port, "PLAYREC", "epg2vdr", opt, result); + free(opt); + + if (status != success) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "%s", result); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Stop Key +//*************************************************************************** + +int cEpgHttpd::doHitKey(MHD_Connection* tcp, json_t* obj) +{ + int alive; + const char* ip = 0; + int port = 0; + char result[512+TB] = ""; + + const char* vdruuid = getStrParameter(tcp, "vdruuid"); + const char* key = getStrParameter(tcp, "key"); + + if (isEmpty(vdruuid) || isEmpty(key)) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Missing at least the vdr reference or the key code"); + + alive = ipOfVdr(vdruuid, ip, port); + + if (!alive || isEmpty(ip) || !port) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Can't send key code, VDR is not alive"); + + if (triggerVdr(ip, port, "HITK", 0, key, result) != success) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "%s", result); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Log +//*************************************************************************** + +int cEpgHttpd::doLog(MHD_Connection* tcp, json_t* obj) +{ + int level = getIntParameter(tcp, "loglevel", 1); + const char* msg = getStrParameter(tcp, "message", ""); + char* buffer = (char*)malloc(strlen(msg)+TB); + + urlUnescape(buffer, msg); + + if (!isEmpty(buffer)) + tell(level, "webif: %s", buffer); + + free(buffer); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Debug +//*************************************************************************** + +int cEpgHttpd::doDebug(MHD_Connection* tcp, json_t* obj) +{ + // 'GET' parameters + + EpgdConfig.loglevel = getIntParameter(tcp, "loglevel", EpgdConfig.loglevel); + + tell(0, "Set log level to (%d)", EpgdConfig.loglevel); + + return buildResponse(obj, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Channel Switch +//*************************************************************************** + +int cEpgHttpd::doChannelSwitch(MHD_Connection* tcp, json_t* obj) +{ + // where channel can <number> | <name> | <id> + + const char* channelPar = getStrParameter(tcp, "channel", ""); + const char* uuidPar = getStrParameter(tcp, "uuid"); + int statusCode = MHD_HTTP_INTERNAL_SERVER_ERROR; + char* message = 0; + + tell(0, "Switching vdr '%s' to channel '%s'", uuidPar, channelPar); + + vdrDb->clear(); + vdrDb->setValue("Uuid", uuidPar); + + if (vdrDb->find()) + { + if (strcasecmp(vdrState->getStrValue(), "attached") == 0) + { + const char* ip = vdrIp->getStrValue(); + unsigned int port = vdrSvdrp->getIntValue(); + + if (!port) + port = 6419; + + cSvdrpClient cl(ip, port); + + // open tcp connection + + if (cl.open() == success) + { + char* command = 0; + cList<cLine> result; + + asprintf(&command, "CHAN %s", channelPar); + + if (!cl.send(command)) + { + asprintf(&message, "Error: Send '%s' failed!", command); + } + else + { + int status = cl.receive(&result); + + if (result.First() && result.First()->Text()) + asprintf(&message, "Send '%s' succeeded; Got %d '%s'", command, status, result.First()->Text()); + else + asprintf(&message, "Send '%s' succeeded but missing response from vdr", command); + + statusCode = MHD_HTTP_OK; + } + + free(command); + cl.close(no); + } + else + { + asprintf(&message, "Error: Can't switch channel, vdr '%s' svdrp connect failed!", uuidPar); + } + } + else + { + asprintf(&message, "Info: Can't switch channel, vdr '%s' not running!", uuidPar); + } + } + else + { + asprintf(&message, "Info: Can't switch channel, vdr '%s' not known!", uuidPar); + } + + tell(0, "%s", message); + + vdrDb->reset(); + + buildResponse(obj, statusCode, "%s", message); + free(message); + + return statusCode; +} + +//*************************************************************************** +// Do Channel Logo +//*************************************************************************** + +int cEpgHttpd::doChannelLogo(MHD_Connection* tcp, json_t* obj, MemoryStruct* data) +{ + // 'GET' parameters + + long int logoUpper; + long int logoById; + char logoSuffix[sizeMaxParameterValue+TB]; + + const char* id = getStrParameter(tcp, "id"); + int maxW = getIntParameter(tcp, "maxW", 100); + int maxH = getIntParameter(tcp, "maxH", 80); + + if (isEmpty(id)) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Missing channel id in request"); + + getParameter("epgd", "logoUpperCase", logoUpper); + getParameter("epgd", "logoById", logoById); + getParameter("epgd", "logoSuffix", logoSuffix); + + mapDb->clear(); + mapDb->setValue("ChannelId", id); + + if (selectMapById->find()) + { + if (!isEmpty(mapChannelName->getStrValue())) + { + char* path; + char* cnlName = strdup(mapChannelName->getStrValue()); + char* cnlId = strdup(id); + Imlib_Image image; + Imlib_Load_Error err; + + toCase(logoUpper ? cUpper : cLower, cnlName); + toCase(logoUpper ? cUpper : cLower, cnlId); + + asprintf(&path, "%s/channellogos/%s.%s", EpgdConfig.httpPath, + logoById ? cnlId : cnlName, logoSuffix); + + data->modTime = fileModTime(path); + + tell(3, "file: %s; expire: %s", l2pTime(data->modTime).c_str(), l2pTime(data->expireAt).c_str()); + + if (!data->expireAt || data->modTime > data->expireAt) + { + if (strcasecmp(suffixOf(path), "svg") == 0) + { + if (loadFromFile(path, data) == success) + sprintf(data->name, "%.*s", (int)sizeof(data->name), path); + } + else + { + image = imlib_load_image_with_error_return(path, &err); + + if (image) + { + scaleImageToJpegBuffer(image, data, maxW, maxH); + sprintf(data->contentType, "image/jpg"); + + imlib_context_set_image(image); + imlib_free_image(); + } + else + tell(2, "The image '%s' could not be loaded, error was '%s' (%d)", + path, strImlibError(err), err); + } + } + + free(cnlId); + free(path); + free(cnlName); + } + } + else + tell(1, "Info: Channelname for '%s' unknown", id); + + selectMapById->freeResult(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do EPG Image +//*************************************************************************** + +int cEpgHttpd::doEpgImage(MHD_Connection* tcp, json_t* obj, MemoryStruct* data) +{ + // 'GET' parameters + + int useId = getIntParameter(tcp, "id"); + int maxW = getIntParameter(tcp, "maxW"); + int maxH = getIntParameter(tcp, "maxH"); + int no = getIntParameter(tcp, "no"); + + data->clear(); + + if (!useId) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Missing event id in request"); + + tell(3, "lookup image for (%d/%d)", useId, no); + + useeventsDb->clear(); + useeventsDb->setValue("USEID", useId); + + if (selectEvent->find()) + { + tEventId id = imageid.getBigintValue(); + + tell(3, "found event for useid %d -> eventid is %llu", useId, id); + + imageRefDb->clear(); + imageRefDb->setBigintValue("EventId", id); + imageRefDb->setValue("Lfn", no); + + if (imageRefDb->find()) + { + const char* imageName = imagerefImgName->getStrValue(); + + imageDb->clear(); + imageDb->setValue("ImgName", imageName); + + if (imageDb->find() && !imageImage->isNull()) + { + data->modTime = imageUpdSp->getIntValue(); + + tell(3, "file: %s; expire: %s", l2pTime(data->modTime).c_str(), l2pTime(data->expireAt).c_str()); + + if (!data->expireAt || data->modTime > data->expireAt) + { + data->size = imageImage->getStrValueSize(); + + tell(3, "found image with %ld bytes", data->size); + + // imageImage->getStrValue(); + + data->memory = (char*)malloc(data->size); + memcpy(data->memory, imageImage->getStrValue(), data->size); + + scaleJpegBuffer(data, maxW, maxH); + sprintf(data->contentType, "image/jpg"); + } + } + + imageDb->reset(); + } + + imageRefDb->reset(); + } + + selectEvent->freeResult(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Movie Media (images) +//*************************************************************************** + +int cEpgHttpd::doMovieMedia(MHD_Connection* tcp, json_t* obj, MemoryStruct* data) +{ + // 'GET' parameters + + int movieId = getIntParameter(tcp, "movie_id", na); + int actorId = getIntParameter(tcp, "actor_id", na); + int mediaType = getIntParameter(tcp, "media_type", na); + int maxW = getIntParameter(tcp, "maxW"); + int maxH = getIntParameter(tcp, "maxH"); + + data->clear(); + + if (actorId) + movieId = 0; + + if (movieId == na || actorId == na || mediaType == na) + return buildResponse(obj, MHD_HTTP_BAD_REQUEST, "Missing madatory request parameter"); + + tell(3, "lookup movie media for (%d/%d/%d)", movieId, actorId, mediaType); + + movieMediaDb->clear(); + movieMediaDb->setValue("MovieId", movieId); + movieMediaDb->setValue("ActorId", actorId); + movieMediaDb->setValue("MediaType", mediaType); + + if (movieMediaDb->find() && !moviemediaMediaContent->isNull()) + { + tell(3, "found movie media for %d/%d/%d", movieId, actorId, mediaType); + + // fake modTime until movieMediaDb table dont support updsp !! + + // data->modTime = movieMediaDb->getIntValue("UpdSp"); + + data->modTime = data->expireAt ? data->expireAt : time(0); // fake!! + + tell(3, "Media: modified at: %s; expire at: %s", l2pTime(data->modTime).c_str(), l2pTime(data->expireAt).c_str()); + + if (!data->expireAt || data->modTime > data->expireAt) + { + data->size = moviemediaMediaContent->getStrValueSize(); + + tell(3, "found media with %ld bytes", data->size); + + data->memory = (char*)malloc(data->size); + memcpy(data->memory, moviemediaMediaContent->getStrValue(), data->size); + + scaleJpegBuffer(data, maxW, maxH); + sprintf(data->contentType, "image/jpg"); + } + } + + movieMediaDb->reset(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Series Media (images) +//*************************************************************************** + +int cEpgHttpd::doSeriesMedia(MHD_Connection* tcp, json_t* obj, MemoryStruct* data) +{ + // 'GET' parameters + + int seriesId = getIntParameter(tcp, "series_id", na); + int seasonNumber = getIntParameter(tcp, "season_number", na); + int episodeId = getIntParameter(tcp, "episode_id", na); + int actorId = getIntParameter(tcp, "actor_id", 0); + int mediaType = getIntParameter(tcp, "media_type", na); + int maxW = getIntParameter(tcp, "maxW"); + int maxH = getIntParameter(tcp, "maxH"); + + data->clear(); + + if (actorId) + { + mediaType = 11; + seasonNumber = 0; + episodeId = 0; + } + + if (seriesId == na || seasonNumber == na || episodeId == na || mediaType == na) + return buildResponse(obj, MHD_HTTP_BAD_REQUEST, "Missing madatory request parameter"); + + tell(3, "lookup series media for (%d/%d/%d/%d/%d)", seriesId, seasonNumber, episodeId, actorId, mediaType); + + seriesMediaDb->clear(); + seriesMediaDb->setValue("SERIESID", seriesId); + seriesMediaDb->setValue("SEASONNUMBER", seasonNumber); + seriesMediaDb->setValue("EPISODEID", episodeId); + seriesMediaDb->setValue("ACTORID", actorId); + seriesMediaDb->setValue("MEDIATYPE", mediaType); + + if (seriesMediaDb->find() && !seriesmediaMediaContent->isNull()) + { + data->modTime = seriesMediaDb->getIntValue("UPDSP"); + + tell(3, "Found series media for (%d/%d/%d/%d/%d)", seriesId, seasonNumber, episodeId, actorId, mediaType); + tell(3, "Media: modified at: %s; expire at: %s", l2pTime(data->modTime).c_str(), l2pTime(data->expireAt).c_str()); + + if (!data->expireAt || data->modTime > data->expireAt) + { + data->size = seriesmediaMediaContent->getStrValueSize(); + + tell(3, "found media with %ld bytes", data->size); + + data->memory = (char*)malloc(data->size); + memcpy(data->memory, seriesmediaMediaContent->getStrValue(), data->size); + + scaleJpegBuffer(data, maxW, maxH); + sprintf(data->contentType, "image/jpg"); + } + } + + seriesMediaDb->reset(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Channels +//*************************************************************************** + +int cEpgHttpd::doChannels(MHD_Connection* tcp, json_t* obj) +{ + json_t* oChannel = json_array(); + json_t* oChanData = 0; + json_t* oSources = 0; + std::string last = ""; + + mapDb->clear(); + + for (int found = selectAllMap->find(); found; found = selectAllMap->fetch()) + { + const char* id = mapChannelId->getStrValue(); + + if (last != id) + { + // push last object - if one + + if (oChanData) + json_array_append_new(oChannel, oChanData); + + oChanData = json_object(); + oSources = json_object(); + json_object_set_new(oChanData, "sources", oSources); + + addFieldToJson(oChanData, mapDb, "CHANNELID", yes); + addFieldToJson(oChanData, mapDb, "CHANNELNAME", yes, "name"); + addFieldToJson(oChanData, mapDb, "ORDER"); + addFieldToJson(oChanData, mapDb, "VISIBLE"); + + last = id; + } + + json_t* oSource = json_object(); + + addFieldToJson(oSource, mapDb, "ExternalId"); + addFieldToJson(oSource, mapDb, "Merge"); + + json_object_set_new(oSources, mapSource->getStrValue(), oSource); + } + + if (oChanData && last.length()) + json_array_append_new(oChannel, oChanData); + + selectAllMap->freeResult(); + + json_object_set_new(obj, "channels", oChannel); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Genres +//*************************************************************************** + +int cEpgHttpd::doGenres(MHD_Connection* tcp, json_t* obj) +{ + json_t* oGenres = json_array(); + + useeventsDb->clear(); + + for (int found = selectGenres->find(); found; found = selectGenres->fetch()) + if (!isEmpty(eventsGenre->getStrValue())) + json_array_append_new(oGenres, json_string(eventsGenre->getStrValue())); + + selectGenres->freeResult(); + + json_object_set_new(obj, "genres", oGenres); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Categories +//*************************************************************************** + +int cEpgHttpd::doCategories(MHD_Connection* tcp, json_t* obj) +{ + json_t* oCategories = json_array(); + + useeventsDb->clear(); + + for (int found = selectCategories->find(); found; found = selectCategories->fetch()) + if (!isEmpty(eventsCategory->getStrValue())) + json_array_append_new(oCategories, json_string(eventsCategory->getStrValue())); + + selectCategories->freeResult(); + + json_object_set_new(obj, "categories", oCategories); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Vdrs +//*************************************************************************** + +int cEpgHttpd::doVdrs(MHD_Connection* tcp, json_t* obj) +{ + json_t* oVdrs = json_object(); + + vdrDb->clear(); + + for (int found = selectVdrs->find(); found; found = selectVdrs->fetch()) + { + const char* uuid = vdrUuid->getStrValue(); + int share = vdrDb->getIntValue("SHAREINWEB"); + int svdrp = vdrSvdrp->getIntValue(); + + if (share && svdrp && !isEmpty(uuid) && strcmp(uuid, "epgd") != 0) + { + json_t* o = json_object(); + cDbTableDef* def = vdrDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + { + if (!def->getField(i)->hasType(cDBS::ftMeta) && + !def->getField(i)->hasName("UUID") && + !vdrDb->getValue(def->getField(i))->isNull()) + addFieldToJson(o, vdrDb->getValue(def->getField(i))); + } + + json_object_set_new(oVdrs, uuid, o); + } + } + + selectVdrs->freeResult(); + json_object_set_new(obj, "vdrs", oVdrs); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Users +//*************************************************************************** + +int cEpgHttpd::doUsers(MHD_Connection* tcp, json_t* obj) +{ + json_t* oUsers = json_object(); + + userDb->clear(); + + for (int found = selectUsers->find(); found; found = selectUsers->fetch()) + { + json_t* o = json_object(); + + addFieldToJson(o, userDb, "USER"); + addFieldToJson(o, userDb, "ACTIVE"); + addFieldToJson(o, userDb, "RIGHTS"); + + json_object_set_new(oUsers, userDb->getStrValue("USER"), o); + } + + selectUsers->freeResult(); + + json_object_set_new(obj, "users", oUsers); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Proxy (webcontent) +//*************************************************************************** + +int cEpgHttpd::doProxy(MHD_Connection* tcp, json_t* obj, MemoryStruct* data) +{ + // 'GET' parameters + + const char* typeId = getStrParameter(tcp, "id"); + char* url = 0; + int size = 0; + int statusCode = MHD_HTTP_OK; + + data->clear(); + + if (strcasecmp(typeId, "vdr") == 0) + { + // const char* uuidPar = getStrParameter(tcp, "uuid"); + + // todo Jörg: Könntest du hier über SVDRP und LSTE alle Kanäle + // holen und einfach als Textliste zurückgeben + + return buildResponse(obj, MHD_HTTP_NOT_IMPLEMENTED, "not implemented yet"); + } + + else if (strcasecmp(typeId, "channelpedia") == 0) + { + asprintf(&url, "http://channelpedia.yavdr.com/gen/%s", + getStrParameter(tcp, "path", "")); + } + + else if (strcasecmp(typeId, "constabel") == 0) + { + asprintf(&url, "%s/eplist.cgi?action=show&file=%s", + EpgdConfig.seriesUrl, + getStrParameter(tcp, "title", "")); + } + + if (!url) + return buildResponse(obj, MHD_HTTP_BAD_REQUEST, "Missing id in request"); + + if (curl.downloadFile(url, size, data) != success) + statusCode = MHD_HTTP_NOT_FOUND; + + free(url); + + return statusCode; +} + +//*************************************************************************** +// Do Event +//*************************************************************************** + +int cEpgHttpd::doEvent(MHD_Connection* tcp, json_t* obj, MemoryStruct* data) +{ + // 'GET' parameters + + int id = getIntParameter(tcp, "id"); + + // or .. time and channel + + time_t time = getIntParameter(tcp, "time"); + const char* channelid= getStrParameter(tcp, "channelid"); + + // check + + if (!id && !time && !channelid) + return buildResponse(obj, MHD_HTTP_BAD_REQUEST, "Missing event id or time and channel in request"); + + cDbStatement* select = id ? selectEvent : selectEventByTime; + + // ... + + useeventsDb->clear(); + useeventsDb->setValue("USEID", id); + useeventsDb->setValue("STARTTIME", time); + useeventsDb->setValue("CHANNELID", channelid); + endTime.setValue(time); + + if (select->find()) + { + data->modTime = eventsUpdSp->getIntValue(); + + tell(3, "file: %s; expire: %s", l2pTime(data->modTime).c_str(), l2pTime(data->expireAt).c_str()); + + if (!data->expireAt || data->modTime > data->expireAt) + { + json_t* oEvtData = json_object(); + json_t* oEpiData = json_object(); + + addFieldToJson(oEvtData, useeventsDb, "USEID", no, "id"); + addFieldToJson(oEvtData, useeventsDb, "CHANNELID"); + addFieldToJson(oEvtData, useeventsDb, "STARTTIME"); + addFieldToJson(oEvtData, useeventsDb, "DURATION"); + addFieldToJson(oEvtData, useeventsDb, "CATEGORY"); + addFieldToJson(oEvtData, useeventsDb, "GENRE"); + addFieldToJson(oEvtData, useeventsDb, "TITLE"); + addFieldToJson(oEvtData, useeventsDb, "SHORTTEXT"); + addFieldToJson(oEvtData, useeventsDb, "IMAGECOUNT"); + + addFieldToJson(oEvtData, useeventsDb, "LONGDESCRIPTION"); + addFieldToJson(oEvtData, useeventsDb, "CNTLONGDESCRIPTION"); + addFieldToJson(oEvtData, useeventsDb, "SHORTDESCRIPTION"); + addFieldToJson(oEvtData, useeventsDb, "PARENTALRATING"); + addFieldToJson(oEvtData, useeventsDb, "ACTOR"); + addFieldToJson(oEvtData, useeventsDb, "AUDIO"); + addFieldToJson(oEvtData, useeventsDb, "COUNTRY"); + addFieldToJson(oEvtData, useeventsDb, "DIRECTOR"); + addFieldToJson(oEvtData, useeventsDb, "FLAGS"); + addFieldToJson(oEvtData, useeventsDb, "MUSIC"); + addFieldToJson(oEvtData, useeventsDb, "PRODUCER"); + addFieldToJson(oEvtData, useeventsDb, "SCREENPLAY"); + addFieldToJson(oEvtData, useeventsDb, "SHORTREVIEW"); + addFieldToJson(oEvtData, useeventsDb, "NUMRATING"); + addFieldToJson(oEvtData, useeventsDb, "TXTRATING"); + addFieldToJson(oEvtData, useeventsDb, "TIPP"); + addFieldToJson(oEvtData, useeventsDb, "TOPIC"); + addFieldToJson(oEvtData, useeventsDb, "YEAR"); + addFieldToJson(oEvtData, useeventsDb, "RATING"); + addFieldToJson(oEvtData, useeventsDb, "MODERATOR"); + addFieldToJson(oEvtData, useeventsDb, "COMMENTATOR"); + addFieldToJson(oEvtData, useeventsDb, "OTHER"); + addFieldToJson(oEvtData, useeventsDb, "GUEST"); + addFieldToJson(oEvtData, useeventsDb, "CAMERA"); + addFieldToJson(oEvtData, &merge); + + // timer for this Event pending? + + timerDb->clear(); + timerDb->setValue("EVENTID", useeventsDb->getIntValue("USEID")); + timerDb->setValue("CHANNELID", useeventsDb->getStrValue("CHANNELID")); + + if (selectTimerByEventId->find()) + addFieldToJson(oEvtData, timerDb, "ID", no, "TIMERID"); + + selectTimerByEventId->freeResult(); + + // epispode data + + addFieldToJson(oEpiData, useeventsDb, "EPISODENAME", yes, "episodename"); + addFieldToJson(oEpiData, useeventsDb, "EPISODESHORTNAME", yes, "shortname"); + addFieldToJson(oEpiData, useeventsDb, "EPISODEPARTNAME", yes, "partname"); + addFieldToJson(oEpiData, useeventsDb, "EPISODEEXTRACOL1", yes, "extracol1"); + addFieldToJson(oEpiData, useeventsDb, "EPISODEEXTRACOL2", yes, "extracol2"); + addFieldToJson(oEpiData, useeventsDb, "EPISODEEXTRACOL3", yes, "extracol3"); + addFieldToJson(oEpiData, useeventsDb, "EPISODESEASON", yes, "season"); + addFieldToJson(oEpiData, useeventsDb, "EPISODEPART", yes, "part"); + addFieldToJson(oEpiData, useeventsDb, "EPISODEPARTS", yes, "parts"); + addFieldToJson(oEpiData, useeventsDb, "EPISODENUMBER", yes, "number"); + + // --------------------- + // collect scraper data + + json_t* oScraperData = json_object(); + + collectScraperData(oScraperData, + useeventsDb->getIntValue("SCRMOVIEID"), + useeventsDb->getIntValue("SCRSERIESID"), + useeventsDb->getIntValue("SCRSERIESEPISODE")); + + // ----------------------- + // matching recordings + + json_t* oRecordings = json_array(); + + recordingListDb->clear(); + recordingListDb->setValue("TITLE", useeventsDb->getStrValue("TITLE")); + recordingListDb->setValue("SHORTTEXT", useeventsDb->getStrValue("SHORTTEXT")); + + for (int f = selectRecordingForEventByLv->find(); f; f = selectRecordingForEventByLv->fetch()) + { + json_t* oRecData = json_object(); + + if (recordingListDb->getIntValue("FSK") == 1) // check FSK + { + if (!currentSession || !hasUserMask(currentSession->rights, umFsk)) + { + tell(1, "Skipping recording '%s' due FSK flag", recordingListDb->getStrValue("TITLE")); + continue; + } + } + + addFieldToJson(oRecData, recordingListDb, "NAME"); + addFieldToJson(oRecData, recordingListDb, "TITLE"); + addFieldToJson(oRecData, recordingListDb, "SHORTTEXT"); + addFieldToJson(oRecData, recordingListDb, "STARTTIME"); + addFieldToJson(oRecData, recordingListDb, "OWNER"); + addFieldToJson(oRecData, recordingListDb, "MD5PATH"); + addFieldToJson(oRecData, recordingListDb, "PATH"); + addFieldToJson(oRecData, recordingListDb, "DURATION"); + addFieldToJson(oRecData, recordingListDb, "OWNER"); + addFieldToJson(oRecData, &matchDensityTitle); + addFieldToJson(oRecData, &matchDensityShorttext); + + json_array_append_new(oRecordings, oRecData); + + tell(2, "Found recording for '%s' wich a match density of (%ld%%/%ld%%)", + recordingListDb->getStrValue("TITLE"), + matchDensityTitle.getIntValue(), matchDensityShorttext.getIntValue()); + } + + selectRecordingForEventByLv->freeResult(); + + // final + + json_object_set_new(oEvtData, "recordings", oRecordings); + json_object_set_new(oEvtData, "scraper", oScraperData); + json_object_set_new(oEvtData, "episode", oEpiData); + json_object_set_new(obj, "event", oEvtData); + } + } + else + { + tell(0, "Warning: Event '%d' not found", id); + } + + select->freeResult(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Events +//*************************************************************************** + +int cEpgHttpd::doEvents(MHD_Connection* tcp, json_t* obj) +{ + json_t* oEvent = json_array(); + cDbStatement* select; + + // 'GET' parameters + + time_t begTimePar = getIntParameter(tcp, "time"); + time_t endTimePar = getIntParameter(tcp, "endtime"); + const char* channelidPar = getStrParameter(tcp, "channelid", "%"); // !! set default to "%" + int getNext = getIntParameter(tcp, "next", 0); + + // check ... + + if (begTimePar < time(0) - 2*tmeSecondsPerDay) + { + tell(0, "Error: Requested time '%s' out of range!", l2pTime(begTimePar).c_str()); + } + else + { + // prepare ... + + useeventsDb->clear(); + + if (!endTimePar) // events running at specific time + { + if (getNext > 0) + { + select = selectEventsNext; + useeventsDb->setValue("STARTTIME", begTimePar); + + tell(2, "Select events starting after '%s'", l2pTime(begTimePar).c_str()); + } + else + { + select = selectEventsAt; + useeventsDb->setValue("STARTTIME", begTimePar); + endTime.setValue(begTimePar); + + tell(2, "Select events running at '%s'(%ld), channelid '%s'", + l2pTime(begTimePar).c_str(), begTimePar, channelidPar); + } + } + else // events starting in specified range + { + select = selectEventsStartInRange; + useeventsDb->setValue("StartTime", begTimePar); + startTime.setValue(endTimePar); + + tell(2, "Select events starting between '%s'(%ld) and '%s'(%ld), channelid '%s'", + l2pTime(begTimePar).c_str(), begTimePar, l2pTime(endTimePar).c_str(), endTimePar, channelidPar); + } + + useeventsDb->setValue("ChannelId", channelidPar); + + // query ... + + for (int found = select->find(); found; found = select->fetch()) + { + json_t* oEvtData = json_object(); + + addFieldToJson(oEvtData, useeventsDb, "USEID", no, "id"); + addFieldToJson(oEvtData, useeventsDb, "CHANNELID"); + addFieldToJson(oEvtData, useeventsDb, "STARTTIME"); + addFieldToJson(oEvtData, useeventsDb, "DURATION"); + addFieldToJson(oEvtData, useeventsDb, "CATEGORY"); + addFieldToJson(oEvtData, useeventsDb, "GENRE"); + addFieldToJson(oEvtData, useeventsDb, "TITLE"); + addFieldToJson(oEvtData, useeventsDb, "SHORTTEXT"); + addFieldToJson(oEvtData, useeventsDb, "SHORTDESCRIPTION"); + addFieldToJson(oEvtData, useeventsDb, "NUMRATING"); + addFieldToJson(oEvtData, useeventsDb, "TIPP"); + addFieldToJson(oEvtData, useeventsDb, "IMAGECOUNT"); + + // timer for this Event pending? + + timerDb->clear(); + timerDb->setValue("EVENTID", useeventsDb->getIntValue("USEID")); + timerDb->setValue("CHANNELID", useeventsDb->getStrValue("CHANNELID")); + + if (selectTimerByEventId->find()) + addFieldToJson(oEvtData, timerDb, "ID", no, "TIMERID"); + + selectTimerByEventId->freeResult(); + + json_array_append_new(oEvent, oEvtData); + } + + select->freeResult(); + } + + json_object_set_new(obj, "events", oEvent); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Timer Jobs +//*************************************************************************** + +int cEpgHttpd::doTimerJobs(MHD_Connection* tcp, json_t* obj) +{ + json_t* oTimer = json_array(); + + // prepare ... + + timerDb->clear(); + + // query pending timer actions + + for (int found = selectPendingTimerActions->find(); found; found = selectPendingTimerActions->fetch()) + { + json_t* oData = json_object(); + + cDbTableDef* def = timerDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + addFieldToJson(oData, timerDb->getValue(def->getField(i))); + + json_array_append_new(oTimer, oData); + } + + selectPendingTimerActions->freeResult(); + + json_object_set_new(obj, "timers", oTimer); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Done Timers +//*************************************************************************** + +int cEpgHttpd::doDoneTimers(MHD_Connection* tcp, json_t* obj) +{ + json_t* oTimer = json_array(); + + // prepare ... + + timersDoneDb->clear(); + + // query pending and failed timers ... + + for (int found = selectDoneTimers->find(); found; found = selectDoneTimers->fetch()) + { + json_t* oData = json_object(); + + addFieldToJson(oData, timersDoneDb, "ID"); + addFieldToJson(oData, timersDoneDb, "STATE"); + addFieldToJson(oData, timersDoneDb, "STARTTIME"); + addFieldToJson(oData, timersDoneDb, "DURATION"); + addFieldToJson(oData, timersDoneDb, "TITLE"); + addFieldToJson(oData, timersDoneDb, "SHORTTEXT"); + addFieldToJson(oData, timersDoneDb, "CHANNELID"); + addFieldToJson(oData, timersDoneDb, "AUTOTIMERID"); + addFieldToJson(oData, timersDoneDb, "AUTOTIMERNAME"); + addFieldToJson(oData, timersDoneDb, "EXPRESSION"); + + json_array_append_new(oTimer, oData); + } + + selectDoneTimers->freeResult(); + + json_object_set_new(obj, "donetimers", oTimer); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Done Timer +//*************************************************************************** + +int cEpgHttpd::doDoneTimer(MHD_Connection* tcp, json_t* obj) +{ + int id = getIntParameter(tcp, "id"); + + timersDoneDb->clear(); + timersDoneDb->setValue("ID", id); + + // query + + if (timersDoneDb->find()) + { + json_t* oTimer = json_object(); + cDbTableDef* def = timersDoneDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + { + if (!def->getField(i)->hasType(cDBS::ftMeta)) + addFieldToJson(oTimer, timersDoneDb->getValue(def->getField(i))); + } + + json_object_set_new(obj, "donetimer", oTimer); + } + else + { + timersDoneDb->reset(); + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Done timer '%d' not found", id); + } + + timersDoneDb->reset(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Parameters +//*************************************************************************** + +int cEpgHttpd::doParameters(MHD_Connection* tcp, json_t* obj) +{ + json_t* oParameters = json_array(); + int needLg = needLogin(); + + // prepare ... + + parametersDb->clear(); + + // work ... + + for (int i = 0; cParameters::parameters[i].name != 0; i++) + { + json_t* oData = json_object(); + const char* value; + Parameter* definition = &cParameters::parameters[i]; + std::string user = std::string("@") + (currentSession ? currentSession->user : std::string("")); + std::string owner = definition->owner; + + // skip invisible + + if (!definition || !definition->visible) + continue; + + // if login required (needLogin is set) and no session active (currentSession) + // only reply the "needLogin" parameter + + if (!currentSession && needLg && strcasecmp(definition->name, "needLogin") != 0) + continue; + + if (currentSession && definition->owner[0] == '@') + owner = "@" + currentSession->user; + + json_object_set_new(oData, "owner", json_string(owner.c_str())); + json_object_set_new(oData, "name", json_string(definition->name)); + + parametersDb->setValue("OWNER", owner.c_str()); + parametersDb->setValue("NAME", definition->name); + + if (parametersDb->find()) + value = parametersDb->getStrValue("VALUE"); + else + value = definition->def; + + parametersDb->reset(); + + json_object_set_new(oData, "value", json_string(value)); + json_object_set_new(oData, "type", json_integer(definition->type)); + json_object_set_new(oData, "default", json_string(definition->def)); + json_object_set_new(oData, "valexp", json_string(definition->regexp)); + json_object_set_new(oData, "readonly", json_integer(definition->readonly)); + + json_array_append_new(oParameters, oData); + } + + json_object_set_new(obj, "parameters", oParameters); + json_object_set_new(obj, "timezone", json_integer(isDST() ? timezone - 3600 : timezone)); + tell(2, "daylight (%d); timezone is (%ld)", isDST(), timezone); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Recording Directories +//*************************************************************************** + +int cEpgHttpd::doRecDirs(MHD_Connection* tcp, json_t* obj) +{ + json_t* oDirectories = json_array(); + + // prepare ... + + recordingDirDb->clear(); + + // query ... + + for (int found = selectRecordingDirs->find(); found; found = selectRecordingDirs->fetch()) + { + json_t* oData = json_object(); + + cDbTableDef* def = recordingDirDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + if (!def->getField(i)->hasType(cDBS::ftMeta)) + addFieldToJson(oData, recordingDirDb->getValue(def->getField(i))); + + json_array_append_new(oDirectories, oData); + } + + selectRecordingDirs->freeResult(); + + json_object_set_new(obj, "recordingdirs", oDirectories); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Timers +//*************************************************************************** + +int cEpgHttpd::doTimers(MHD_Connection* tcp, json_t* obj) +{ + json_t* oTimer = json_array(); + long autotimerid = getIntParameter(tcp, "autotimerid", na); + + const char* state = getStrParameter(tcp, "state", ""); + const char* action = getStrParameter(tcp, "action", ""); + const char* nstate = getStrParameter(tcp, "notstate", ""); + const char* naction = getStrParameter(tcp, "notaction", ""); + + // prepare ... + + timerDb->clear(); + + // timerIncState.setValue(incState); + // timerExcState.setValue(excState); + // timerIncAction.setValue(incAction); + // timerExcAction.setValue(excAction); + + tell(2, "Searching timer with state/action '%s/%s'", state, action); + + // query ... + + for (int found = selectAllTimer->find(); found; found = selectAllTimer->fetch()) + { + json_t* oData = json_object(); + + // webif requested timers for specific autotimer? + + if (autotimerid != na && autotimerid != timerDb->getIntValue("AUTOTIMERID")) + continue; + + // state / action + + if (!isEmpty(action) && !strchr(action, *timerDb->getStrValue("ACTION"))) + continue; + + if (!isEmpty(state)&& !strchr(state, *timerDb->getStrValue("STATE"))) + continue; + + if (!isEmpty(naction) && strchr(naction, *timerDb->getStrValue("ACTION"))) + continue; + + if (!isEmpty(nstate) && strchr(nstate, *timerDb->getStrValue("STATE"))) + continue; + + cDbTableDef* def = timerDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + { + if (!def->getField(i)->hasType(cDBS::ftMeta)) + addFieldToJson(oData, timerDb->getValue(def->getField(i))); + } + + addFieldToJson(oData, useeventsDb, "TITLE"); + addFieldToJson(oData, useeventsDb, "SHORTTEXT"); + addFieldToJson(oData, useeventsDb, "SHORTDESCRIPTION"); + addFieldToJson(oData, useeventsDb, "CATEGORY"); + addFieldToJson(oData, useeventsDb, "GENRE"); + addFieldToJson(oData, useeventsDb, "NUMRATING"); + + if (!timerDb->getValue("AUTOTIMERID")->isNull()) + { + // useeventsDb->find(); // get all fields + + searchtimerDb->clear(); + searchtimerDb->setValue("ID", timerDb->getIntValue("AUTOTIMERID")); + + if (searchtimerDb->find()) + search->getDoneFor(searchtimerDb->getRow(), useeventsDb->getRow(), oData); + else + tell(0, "Warning: Searchtimer %ld not found", timerDb->getIntValue("AUTOTIMERID")); + } + + json_array_append_new(oTimer, oData); + } + + selectAllTimer->freeResult(); + + json_object_set_new(obj, "timers", oTimer); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Recordings +//*************************************************************************** + +int cEpgHttpd::doRecordings(MHD_Connection* tcp, json_t* obj) +{ + json_t* oRecording = json_array(); + + // prepare ... + + vdrDb->clear(); + recordingListDb->clear(); + + // query ... + + for (int found = selectAllRecordings->find(); found; found = selectAllRecordings->fetch()) + { + json_t* oData = json_object(); + + if (!vdrDb->getIntValue("SHAREINWEB")) + { + tell(1, "Skipping recording '%s' due to not shareinweb flag", recordingListDb->getStrValue("TITLE")); + continue; + } + + // check FSK + + if (recordingListDb->getIntValue("FSK") == 1) + { + if (!currentSession || !hasUserMask(currentSession->rights, umFsk)) + { + tell(1, "Skipping recording '%s' due FSK flag", recordingListDb->getStrValue("TITLE")); + continue; + } + } + + addFieldToJson(oData, recordingListDb, "NAME"); + addFieldToJson(oData, recordingListDb, "TITLE"); + addFieldToJson(oData, recordingListDb, "SHORTTEXT"); + addFieldToJson(oData, recordingListDb, "STARTTIME"); + addFieldToJson(oData, recordingListDb, "OWNER"); + addFieldToJson(oData, recordingListDb, "MD5PATH"); + addFieldToJson(oData, recordingListDb, "PATH"); + addFieldToJson(oData, recordingListDb, "DURATION"); + addFieldToJson(oData, recordingListDb, "VDRUUID"); + + json_array_append_new(oRecording, oData); + } + + selectAllRecordings->freeResult(); + + json_object_set_new(obj, "recordings", oRecording); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Recording +//*************************************************************************** + +int cEpgHttpd::doRecording(MHD_Connection* tcp, json_t* obj) +{ + json_t* oRecording = json_object(); + + int starttime = getIntParameter(tcp, "starttime"); + const char* md5path = getStrParameter(tcp, "md5path"); + const char* path = getStrParameter(tcp, "path"); + const char* owner = getStrParameter(tcp, "owner", ""); + + // check + + if (!starttime || (!md5path && !path)) + return buildResponse(obj, MHD_HTTP_BAD_REQUEST, "Missing event start time or md5path/path in request"); + + // prepare + + recordingListDb->clear(); + recordingListDb->setValue("STARTTIME", starttime); + recordingListDb->setValue("OWNER", owner); + + if (!isEmpty(md5path)) + { + recordingListDb->setValue("MD5PATH", md5path); + + if (!recordingListDb->find()) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Recording '%s/%d' not found", md5path, starttime); + } + else if (!isEmpty(path)) + { + recordingListDb->setValue("PATH", path); + + if (!selectRecordingByPath->find()) + return buildResponse(obj, MHD_HTTP_NOT_FOUND, "Recording '%s/%d' not found", md5path, starttime); + } + + cDbTableDef* def = recordingListDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + { + if (!def->getField(i)->hasType(cDBS::ftMeta)) + addFieldToJson(oRecording, recordingListDb->getValue(def->getField(i))); + } + + // --------------------- + // collect scraper data + + json_t* oScraperData = json_object(); + + collectScraperData(oScraperData, + recordingListDb->getIntValue("SCRMOVIEID"), + recordingListDb->getIntValue("SCRSERIESID"), + recordingListDb->getIntValue("SCRSERIESEPISODE")); + + // final + + json_object_set_new(oRecording, "scraper", oScraperData); + json_object_set_new(obj, "recording", oRecording); + + recordingListDb->reset(); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Searchtimers +//*************************************************************************** + +int cEpgHttpd::doSearchtimers(MHD_Connection* tcp, json_t* obj) +{ + json_t* oTimer = json_array(); + int count = 0; + + const char* type = getStrParameter(tcp, "type", 0); + + // prepare ... + + searchtimerDb->clear(); + + // query ... + + for (int found = selectAllSearchTimer->find(); found; found = selectAllSearchTimer->fetch()) + { + json_t* oData = json_object(); + cDbTableDef* def = searchtimerDb->getTableDef(); + + if (type && !searchtimerDb->hasValue("TYPE", type)) + continue; + + for (int i = 0; i < def->fieldCount(); i++) + { + if (!def->getField(i)->hasType(cDBS::ftMeta)) + addFieldToJson(oData, searchtimerDb->getValue(def->getField(i))); + } + + json_array_append_new(oTimer, oData); + count++; + } + + selectAllSearchTimer->freeResult(); + json_object_set_new(obj, "searchtimers", oTimer); + tell(3, "Finished searchtimer request with %d results", count); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Search +//*************************************************************************** + +int cEpgHttpd::doSearch(json_t* jInData, json_t* response) +{ + int id = getIntFromJson(jInData, "autotimerid", na); + const char* name = getStringFromJson(jInData, "autotimername", 0); + + int start = getIntFromJson(jInData, "start", 0); + int max = getIntFromJson(jInData, "max", na); // na -> alle, 0 - nur zählen, > 0 - limit + + // with id, use searchtimer ... + + if (id > 0 || !isEmpty(name)) + { + cDbRow* searchTimer = new cDbRow("searchtimers"); + searchTimer->clear(); + searchTimer->setValue("ID", id); + searchTimer->setValue("NAME", name); + search->getSearchMatches(searchTimer, response, start, max); + delete searchTimer; + return MHD_HTTP_OK; + } + + // without id, use given criterias ... + + const char* expression = getStringFromJson(jInData, "expression", ""); + + if (isEmpty(expression)) + return buildResponse(response, MHD_HTTP_BAD_REQUEST, "Ignoring search request need at lease a expression or id!"); + + cDbRow* searchTimer = new cDbRow("searchtimers"); + cDbTableDef* def = searchTimer->getTableDef(); + + searchTimer->clear(); + + for (int i = 0; i < def->fieldCount(); i++) + { + const char* jName = 0; + + if (def->getField(i)->hasType(cDBS::ftMeta) || def->getField(i)->hasType(cDBS::ftPrimary)) + continue; + + getFieldFromJson(jInData, searchTimer, def->getField(i)->getName(), jName); + } + + search->getSearchMatches(searchTimer, response, start, max); + + delete searchTimer; + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Send Mail +//*************************************************************************** + +int cEpgHttpd::doSendMail(json_t* jInData, json_t* response) +{ + char* command = 0; + char mailScript[255+TB]; + int res; + + const char* receiver = getStringFromJson(jInData, "receiver", ""); + const char* body = getStringFromJson(jInData, "body", "test mail"); + const char* subject = getStringFromJson(jInData, "subject", "test"); + const char* mimeType = getStringFromJson(jInData, "mimetype", "text/plain"); + + getParameter("epgd", "mailScript", mailScript); + + if (isEmpty(mailScript)) + return buildResponse(response, MHD_HTTP_BAD_REQUEST, "Missing mailScript in configuration"); + + if (!fileExists(mailScript)) + return buildResponse(response, MHD_HTTP_BAD_REQUEST, "File '%s' not found", mailScript); + + // send HTML mail + + tell(0, "Send mail '%s' with [%s] to '%s'", subject, body, receiver); + + asprintf(&command, "%s '%s' '%s' '%s' %s", mailScript, + subject, body, mimeType, receiver); + + if ((res = system(command)) != 0) + { + if (res == -1) + return buildResponse(response, MHD_HTTP_BAD_REQUEST, + "Error: Command '%s' failed, can't fork process, result was (%s)", + command, strerror(errno)); + else + return buildResponse(response, MHD_HTTP_BAD_REQUEST, + "Error: Result of command '%s' was (%d)", command, res); + } + + free(command); + + return buildResponse(response, MHD_HTTP_OK, "done"); +} + +//*************************************************************************** +// Do Login +//*************************************************************************** + +int cEpgHttpd::doLogin(json_t* jInData, json_t* response) +{ + json_t* oLogin = json_object(); + int accepted = no; + const char* key = getStringFromJson(jInData, "key", ""); + + if (isEmpty(key)) + { + // LOGOUT + + std::map<std::string,Session>::iterator it; + + if (currentSession && (it = sessions.find(currentSession->id)) != sessions.end()) + { + tell(0, "User '%s' for session '%s' logged out", + currentSession->user.c_str(), currentSession->id.c_str()); + + sessions.erase(it); + currentSession = 0; + } + } + else + { + // LOGIN + + userDb->clear(); + userDb->setValue("PASSWD", key); + + accepted = selectUserByMd5->find() && userDb->getIntValue("ACTIVE"); + + if (accepted) + { + Session session; + + session.start = time(0); + session.last = time(0); + session.rights = userDb->getIntValue("RIGHTS"); + session.user = userDb->getStrValue("USER"); + session.id = getUniqueId(); // userDb->getStrValue("PASSWD") + num2Str(session.start); + + sessions[session.id] = session; + + json_object_set_new(oLogin, "user", json_string(userDb->getStrValue("USER"))); + json_object_set_new(oLogin, "rights", json_integer(userDb->getIntValue("RIGHTS"))); + json_object_set_new(oLogin, "session", json_string(session.id.c_str())); + + tell(0, "Login of user '%s' for session '%s' confirmed", + userDb->getStrValue("USER"), session.id.c_str()); + } + } + + if (!accepted) + { + json_object_set_new(oLogin, "user", json_string("")); + json_object_set_new(oLogin, "rights", json_integer(0)); + json_object_set_new(oLogin, "session", json_string("")); + + tell(0, "Warning: Login of '%s' denied", userDb->getStrValue("USER")); + } + + json_object_set_new(response, "login", oLogin); + + return MHD_HTTP_OK; +} + +//*************************************************************************** +// Do Messages +//*************************************************************************** + +int cEpgHttpd::doMessages(MHD_Connection* tcp, json_t* obj) +{ + json_t* oMessages = json_array(); + + // prepare ... + + messageDb->clear(); + + // query messages + + for (int found = selectPendingMessages->find(); found; found = selectPendingMessages->fetch()) + { + json_t* oData = json_object(); + cDbTableDef* def = messageDb->getTableDef(); + + for (int i = 0; i < def->fieldCount(); i++) + addFieldToJson(oData, messageDb->getValue(def->getField(i))); + + json_array_append_new(oMessages, oData); + } + + selectPendingMessages->freeResult(); + + json_object_set_new(obj, "messages", oMessages); + + return MHD_HTTP_OK; +} |