source: titan/minidlna-1.0.22/tivo_commands.c @ 13567

Last change on this file since 13567 was 13567, checked in by obi, 11 years ago

[titan] add minidlna-1.0.22 first step

File size: 20.1 KB
Line 
1/* MiniDLNA media server
2 * Copyright (C) 2009  Justin Maggard
3 *
4 * This file is part of MiniDLNA.
5 *
6 * MiniDLNA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * MiniDLNA is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "config.h"
19#ifdef TIVO_SUPPORT
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <libgen.h>
24#include <time.h>
25
26#include "tivo_utils.h"
27#include "upnpglobalvars.h"
28#include "upnphttp.h"
29#include "upnpsoap.h"
30#include "utils.h"
31#include "sql.h"
32#include "log.h"
33
34void
35SendRootContainer(struct upnphttp * h)
36{
37        char * resp;
38        int len;
39
40        len = asprintf(&resp, "<?xml version='1.0' encoding='UTF-8' ?>\n"
41                        "<TiVoContainer>"
42                         "<Details>"
43                          "<ContentType>x-container/tivo-server</ContentType>"
44                          "<SourceFormat>x-container/folder</SourceFormat>"
45                          "<TotalDuration>0</TotalDuration>"
46                          "<TotalItems>3</TotalItems>"
47                          "<Title>%s</Title>"
48                         "</Details>"
49                         "<ItemStart>0</ItemStart>"
50                         "<ItemCount>3</ItemCount>"
51                         "<Item>"
52                          "<Details>"
53                           "<ContentType>x-container/tivo-photos</ContentType>"
54                           "<SourceFormat>x-container/folder</SourceFormat>"
55                           "<Title>Pictures on %s</Title>"
56                          "</Details>"
57                          "<Links>"
58                           "<Content>"
59                            "<Url>/TiVoConnect?Command=QueryContainer&amp;Container=3</Url>"
60                           "</Content>"
61                          "</Links>"
62                         "</Item>"
63                         "<Item>"
64                          "<Details>"
65                           "<ContentType>x-container/tivo-music</ContentType>"
66                           "<SourceFormat>x-container/folder</SourceFormat>"
67                           "<Title>Music on %s</Title>"
68                          "</Details>"
69                          "<Links>"
70                           "<Content>"
71                            "<Url>/TiVoConnect?Command=QueryContainer&amp;Container=1</Url>"
72                           "</Content>"
73                          "</Links>"
74                         "</Item>"
75                         "<Item>"
76                          "<Details>"
77                           "<ContentType>x-container/tivo-videos</ContentType>"
78                           "<SourceFormat>x-container/folder</SourceFormat>"
79                           "<Title>Videos on %s</Title>"
80                          "</Details>"
81                          "<Links>"
82                           "<Content>"
83                            "<Url>/TiVoConnect?Command=QueryContainer&amp;Container=2</Url>"
84                            "<ContentType>x-container/tivo-videos</ContentType>"
85                           "</Content>"
86                          "</Links>"
87                         "</Item>"
88                        "</TiVoContainer>",
89                        friendly_name, friendly_name, friendly_name, friendly_name);
90        BuildResp_upnphttp(h, resp, len);
91        free(resp);
92        SendResp_upnphttp(h);
93}
94
95char *
96unescape_tag(char * tag)
97{
98        modifyString(tag, "&amp;amp;", "&amp;", 0);
99        modifyString(tag, "&amp;amp;lt;", "&lt;", 0);
100        modifyString(tag, "&amp;lt;", "&lt;", 0);
101        modifyString(tag, "&amp;amp;gt;", "&gt;", 0);
102        modifyString(tag, "&amp;gt;", "&gt;", 0);
103        return tag;
104}
105
106#define FLAG_SEND_RESIZED  0x01
107#define FLAG_NO_PARAMS     0x02
108#define FLAG_VIDEO         0x04
109int callback(void *args, int argc, char **argv, char **azColName)
110{
111        struct Response *passed_args = (struct Response *)args;
112        char *id = argv[0], *class = argv[1], *detailID = argv[2], *size = argv[3], *title = argv[4], *duration = argv[5],
113             *bitrate = argv[6], *sampleFrequency = argv[7], *artist = argv[8], *album = argv[9], *genre = argv[10],
114             *comment = argv[11], *date = argv[12], *resolution = argv[13], *mime = argv[14], *path = argv[15];
115        struct string_s *str = passed_args->str;
116
117        if( strncmp(class, "item", 4) == 0 )
118        {
119                int flags = 0;
120                unescape_tag(title);
121                if( strncmp(mime, "audio", 5) == 0 )
122                {
123                        flags |= FLAG_NO_PARAMS;
124                        strcatf(str, "<Item><Details>"
125                                     "<ContentType>audio/*</ContentType>"
126                                     "<SourceFormat>%s</SourceFormat>"
127                                     "<SourceSize>%s</SourceSize>"
128                                     "<SongTitle>%s</SongTitle>", mime, size, title);
129                        if( date )
130                        {
131                                strcatf(str, "<AlbumYear>%.*s</AlbumYear>", 4, date);
132                        }
133                }
134                else if( strcmp(mime, "image/jpeg") == 0 )
135                {
136                        flags |= FLAG_SEND_RESIZED;
137                        strcatf(str, "<Item><Details>"
138                                     "<ContentType>image/*</ContentType>"
139                                     "<SourceFormat>image/jpeg</SourceFormat>"
140                                     "<SourceSize>%s</SourceSize>", size);
141                        if( date )
142                        {
143                                struct tm tm;
144                                memset(&tm, 0, sizeof(tm));
145                                tm.tm_isdst = -1; // Have libc figure out if DST is in effect or not
146                                strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
147                                strcatf(str, "<CaptureDate>0x%X</CaptureDate>", (unsigned int)mktime(&tm));
148                        }
149                        if( comment )
150                        {
151                                strcatf(str, "<Caption>%s</Caption>", comment);
152                        }
153                }
154                else if( strncmp(mime, "video", 5) == 0 )
155                {
156                        char *episode;
157                        flags |= FLAG_NO_PARAMS;
158                        flags |= FLAG_VIDEO;
159                        strcatf(str, "<Item><Details>"
160                                     "<ContentType>video/x-tivo-mpeg</ContentType>"
161                                     "<SourceFormat>%s</SourceFormat>"
162                                     "<SourceSize>%s</SourceSize>", mime, size);
163                        episode = strstr(title, " - ");
164                        if( episode )
165                        {
166                                strcatf(str, "<Title>%.*s</Title>"
167                                             "<EpisodeTitle>%s</EpisodeTitle>",
168                                             (int)(episode-title), title, episode+3);
169                        }
170                        else
171                        {
172                                strcatf(str, "<Title>%s</Title>", title);
173                        }
174                        if( date )
175                        {
176                                struct tm tm;
177                                memset(&tm, 0, sizeof(tm));
178                                tm.tm_isdst = -1; // Have libc figure out if DST is in effect or not
179                                strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
180                                strcatf(str, "<CaptureDate>0x%X</CaptureDate>", (unsigned int)mktime(&tm));
181                        }
182                        if( comment )
183                        {
184                                strcatf(str, "<Description>%s</Description>", comment);
185                        }
186                }
187                else
188                {
189                        return 0;
190                }
191                strcatf(str, "<Title>%s</Title>", unescape_tag(title));
192                if( artist ) {
193                        strcatf(str, "<ArtistName>%s</ArtistName>", unescape_tag(artist));
194                }
195                if( album ) {
196                        strcatf(str, "<AlbumTitle>%s</AlbumTitle>", unescape_tag(album));
197                }
198                if( genre ) {
199                        strcatf(str, "<MusicGenre>%s</MusicGenre>", unescape_tag(genre));
200                }
201                if( resolution ) {
202                        char *width = strsep(&resolution, "x");
203                        strcatf(str, "<SourceWidth>%s</SourceWidth>"
204                                           "<SourceHeight>%s</SourceHeight>",
205                                           width, resolution);
206                }
207                if( duration ) {
208                        strcatf(str, "<Duration>%d</Duration>",
209                              atoi(strrchr(duration, '.')+1) + (1000*atoi(strrchr(duration, ':')+1))
210                              + (60000*atoi(strrchr(duration, ':')-2)) + (3600000*atoi(duration)));
211                }
212                if( bitrate ) {
213                        strcatf(str, "<SourceBitRate>%s</SourceBitRate>", bitrate);
214                }
215                if( sampleFrequency ) {
216                        strcatf(str, "<SourceSampleRate>%s</SourceSampleRate>", sampleFrequency);
217                }
218                strcatf(str, "</Details><Links><Content>"
219                             "<ContentType>%s</ContentType>"
220                             "<Url>/%s/%s.dat</Url>%s</Content>",
221                             mime,
222                             (flags & FLAG_SEND_RESIZED)?"Resized":"MediaItems", detailID,
223                             (flags & FLAG_NO_PARAMS)?"<AcceptsParams>No</AcceptsParams>":"");
224                if( flags & FLAG_VIDEO )
225                {
226                        char *esc_name = escape_tag(basename(path), 1);
227                        strcatf(str, "<CustomIcon>"
228                                       "<ContentType>video/*</ContentType>"
229                                       "<Url>urn:tivo:image:save-until-i-delete-recording</Url>"
230                                     "</CustomIcon>"
231                                     "<Push><Container>Videos</Container></Push>"
232                                     "<File>%s</File> </Links>", esc_name);
233                        free(esc_name);
234                }
235                else
236                {
237                        strcatf(str, "</Links>");
238                }
239        }
240        else if( strncmp(class, "container", 9) == 0 )
241        {
242                int count;
243                /* Determine the number of children */
244#ifdef __sparc__ /* Adding filters on large containers can take a long time on slow processors */
245                count = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", id);
246#else
247                count = sql_get_int_field(db, "SELECT count(*) from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where PARENT_ID = '%s' and "
248                                              " (MIME in ('image/jpeg', 'audio/mpeg', 'video/mpeg', 'video/x-tivo-mpeg')"
249                                              " or CLASS glob 'container*')", id);
250#endif
251                strcatf(str, "<Item>"
252                             "<Details>"
253                               "<ContentType>x-container/folder</ContentType>"
254                               "<SourceFormat>x-container/folder</SourceFormat>"
255                               "<Title>%s</Title>"
256                               "<TotalItems>%d</TotalItems>"
257                             "</Details>"
258                             "<Links>"
259                               "<Content>"
260                                 "<Url>/TiVoConnect?Command=QueryContainer&amp;Container=%s</Url>"
261                                 "<ContentType>x-tivo-container/folder</ContentType>"
262                               "</Content>"
263                             "</Links>",
264                             unescape_tag(title), count, id);
265        }
266        strcatf(str, "</Item>");
267
268        passed_args->returned++;
269
270        return 0;
271}
272
273#define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.CLASS, o.DETAIL_ID, d.SIZE, d.TITLE," \
274                       " d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST, d.ALBUM, d.GENRE," \
275                       " d.COMMENT, d.DATE, d.RESOLUTION, d.MIME, d.PATH, d.DISC, d.TRACK "
276
277void
278SendItemDetails(struct upnphttp * h, sqlite_int64 item)
279{
280        char *sql;
281        char *zErrMsg = NULL;
282        struct Response args;
283        struct string_s str;
284        int ret;
285        memset(&args, 0, sizeof(args));
286        memset(&str, 0, sizeof(str));
287
288        str.data = malloc(32768);
289        str.size = 32768;
290        str.off = sprintf(str.data, "<?xml version='1.0' encoding='UTF-8' ?>\n<TiVoItem>");
291        args.str = &str;
292        args.requested = 1;
293        asprintf(&sql, SELECT_COLUMNS
294                       "from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
295                       " where o.DETAIL_ID = %lld group by o.DETAIL_ID", item);
296        DPRINTF(E_DEBUG, L_TIVO, "%s\n", sql);
297        ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
298        free(sql);
299        if( ret != SQLITE_OK )
300        {
301                DPRINTF(E_ERROR, L_HTTP, "SQL error: %s\n", zErrMsg);
302                sqlite3_free(zErrMsg);
303        }
304        strcatf(&str, "</TiVoItem>");
305
306        BuildResp_upnphttp(h, str.data, str.off);
307        free(str.data);
308        SendResp_upnphttp(h);
309}
310
311void
312SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int itemCount, char * anchorItem,
313              int anchorOffset, int recurse, char * sortOrder, char * filter, unsigned long int randomSeed)
314{
315        char *resp = malloc(262144);
316        char *sql, *item, *saveptr;
317        char *zErrMsg = NULL;
318        char **result;
319        char *title, *which;
320        char what[10], order[96]={0}, order2[96]={0}, myfilter[256]={0};
321        char str_buf[1024];
322        char type[8];
323        char groupBy[19] = {0};
324        struct Response args;
325        struct string_s str;
326        int totalMatches = 0;
327        int i, ret;
328        memset(&args, 0, sizeof(args));
329        memset(&str, 0, sizeof(str));
330
331        args.str = &str;
332        str.data = resp+1024;
333        str.size = 262144-1024;
334        if( itemCount >= 0 )
335        {
336                args.requested = itemCount;
337        }
338        else
339        {
340                if( itemCount == -100 )
341                        itemCount = 1;
342                args.requested = itemCount * -1;
343        }
344
345        switch( *objectID )
346        {
347                case '1':
348                        strcpy(type, "music");
349                        break;
350                case '2':
351                        strcpy(type, "videos");
352                        break;
353                case '3':
354                        strcpy(type, "photos");
355                        break;
356                default:
357                        strcpy(type, "server");
358                        break;
359        }
360
361        if( strlen(objectID) == 1 )
362        {
363                switch( *objectID )
364                {
365                        case '1':
366                                asprintf(&title, "Music on %s", friendly_name);
367                                break;
368                        case '2':
369                                asprintf(&title, "Videos on %s", friendly_name);
370                                break;
371                        case '3':
372                                asprintf(&title, "Pictures on %s", friendly_name);
373                                break;
374                        default:
375                                asprintf(&title, "Unknown on %s", friendly_name);
376                                break;
377                }
378        }
379        else
380        {
381                item = sql_get_text_field(db, "SELECT NAME from OBJECTS where OBJECT_ID = '%s'", objectID);
382                if( item )
383                {
384                        title = escape_tag(item, 1);
385                        sqlite3_free(item);
386                }
387                else
388                        title = strdup("UNKNOWN");
389        }
390
391        if( recurse )
392        {
393                asprintf(&which, "OBJECT_ID glob '%s$*'", objectID);
394                strcpy(groupBy, "group by DETAIL_ID");
395        }
396        else
397        {
398                asprintf(&which, "PARENT_ID = '%s'", objectID);
399        }
400
401        if( sortOrder )
402        {
403                if( strcasestr(sortOrder, "Random") )
404                {
405                        sprintf(order, "tivorandom(%lu)", randomSeed);
406                        if( itemCount < 0 )
407                                sprintf(order2, "tivorandom(%lu) DESC", randomSeed);
408                        else
409                                sprintf(order2, "tivorandom(%lu)", randomSeed);
410                }
411                else
412                {
413                        short title_state = 0;
414                        item = strtok_r(sortOrder, ",", &saveptr);
415                        while( item != NULL )
416                        {
417                                int reverse=0;
418                                if( *item == '!' )
419                                {
420                                        reverse = 1;
421                                        item++;
422                                }
423                                if( strcasecmp(item, "Type") == 0 )
424                                {
425                                        strcat(order, "CLASS");
426                                        strcat(order2, "CLASS");
427                                }
428                                else if( strcasecmp(item, "Title") == 0 )
429                                {
430                                        /* Explicitly sort music by track then title. */
431                                        if( title_state < 2 && *objectID == '1' )
432                                        {
433                                                if( !title_state )
434                                                {
435                                                        strcat(order, "DISC");
436                                                        strcat(order2, "DISC");
437                                                        title_state = 1;
438                                                }
439                                                else
440                                                {
441                                                        strcat(order, "TRACK");
442                                                        strcat(order2, "TRACK");
443                                                        title_state = 2;
444                                                }
445                                        }
446                                        else
447                                        {
448                                                strcat(order, "TITLE");
449                                                strcat(order2, "TITLE");
450                                                title_state = -1;
451                                        }
452                                }
453                                else if( strcasecmp(item, "CreationDate") == 0 ||
454                                         strcasecmp(item, "CaptureDate") == 0 )
455                                {
456                                        strcat(order, "DATE");
457                                        strcat(order2, "DATE");
458                                }
459                                else
460                                {
461                                        DPRINTF(E_INFO, L_TIVO, "Unhandled SortOrder [%s]\n", item);
462                                        goto unhandled_order;
463                                }
464
465                                if( reverse )
466                                {
467                                        strcat(order, " DESC");
468                                        if( itemCount >= 0 )
469                                                strcat(order2, " DESC");
470                                        else
471                                                strcat(order2, " ASC");
472                                }
473                                else
474                                {
475                                        strcat(order, " ASC");
476                                        if( itemCount >= 0 )
477                                                strcat(order2, " ASC");
478                                        else
479                                                strcat(order2, " DESC");
480                                }
481                                strcat(order, ", ");
482                                strcat(order2, ", ");
483                                unhandled_order:
484                                if( title_state <= 0 )
485                                        item = strtok_r(NULL, ",", &saveptr);
486                        }
487                        if( title_state != -1 )
488                        {
489                                strcat(order, "TITLE ASC, ");
490                                if( itemCount >= 0 )
491                                        strcat(order2, "TITLE ASC, ");
492                                else
493                                        strcat(order2, "TITLE DESC, ");
494                        }
495                        strcat(order, "DETAIL_ID ASC");
496                        if( itemCount >= 0 )
497                                strcat(order2, "DETAIL_ID ASC");
498                        else
499                                strcat(order2, "DETAIL_ID DESC");
500                }
501        }
502        else
503        {
504                sprintf(order, "CLASS, NAME, DETAIL_ID");
505                if( itemCount < 0 )
506                        sprintf(order2, "CLASS DESC, NAME DESC, DETAIL_ID DESC");
507                else
508                        sprintf(order2, "CLASS, NAME, DETAIL_ID");
509        }
510
511        if( filter )
512        {
513                item = strtok_r(filter, ",", &saveptr);
514                for( i=0; item != NULL; i++ )
515                {
516                        if( i )
517                        {
518                                strcat(myfilter, " or ");
519                        }
520                        if( (strcasecmp(item, "x-container/folder") == 0) ||
521                            (strncasecmp(item, "x-tivo-container/", 17) == 0) )
522                        {
523                                strcat(myfilter, "CLASS glob 'container*'");
524                        }
525                        else if( strncasecmp(item, "image", 5) == 0 )
526                        {
527                                strcat(myfilter, "MIME = 'image/jpeg'");
528                        }
529                        else if( strncasecmp(item, "audio", 5) == 0 )
530                        {
531                                strcat(myfilter, "MIME = 'audio/mpeg'");
532                        }
533                        else if( strncasecmp(item, "video", 5) == 0 )
534                        {
535                                strcat(myfilter, "MIME in ('video/mpeg', 'video/x-tivo-mpeg')");
536                        }
537                        else
538                        {
539                                DPRINTF(E_INFO, L_TIVO, "Unhandled Filter [%s]\n", item);
540                                if( i )
541                                {
542                                        ret = strlen(myfilter);
543                                        myfilter[ret-4] = '\0';
544                                }
545                                i--;
546                        }
547                        item = strtok_r(NULL, ",", &saveptr);
548                }
549        }
550        else
551        {
552                strcpy(myfilter, "MIME in ('image/jpeg', 'audio/mpeg', 'video/mpeg', 'video/x-tivo-mpeg') or CLASS glob 'container*'");
553        }
554
555        if( anchorItem )
556        {
557                if( strstr(anchorItem, "QueryContainer") )
558                {
559                        strcpy(what, "OBJECT_ID");
560                        saveptr = strrchr(anchorItem, '=');
561                        if( saveptr )
562                                anchorItem = saveptr + 1;
563                }
564                else
565                {
566                        strcpy(what, "DETAIL_ID");
567                }
568                sqlite3Prng.isInit = 0;
569                sql = sqlite3_mprintf("SELECT %s from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
570                                      " where %s and (%s)"
571                                      " %s"
572                                      " order by %s", what, which, myfilter, groupBy, order2);
573                DPRINTF(E_DEBUG, L_TIVO, "%s\n", sql);
574                if( (sql_get_table(db, sql, &result, &ret, NULL) == SQLITE_OK) && ret )
575                {
576                        for( i=1; i<=ret; i++ )
577                        {
578                                if( strcmp(anchorItem, result[i]) == 0 )
579                                {
580                                        if( itemCount < 0 )
581                                                itemStart = ret - i + itemCount;
582                                        else
583                                                itemStart += i;
584                                        break;
585                                }
586                        }
587                        sqlite3_free_table(result);
588                }
589                sqlite3_free(sql);
590        }
591        args.start = itemStart+anchorOffset;
592        sqlite3Prng.isInit = 0;
593
594        ret = sql_get_int_field(db, "SELECT count(distinct DETAIL_ID) "
595                                    "from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
596                                    " where %s and (%s)",
597                                    which, myfilter);
598        totalMatches = (ret > 0) ? ret : 0;
599        if( itemCount < 0 && !itemStart && !anchorOffset )
600        {
601                args.start = totalMatches + itemCount;
602        }
603
604        sql = sqlite3_mprintf(SELECT_COLUMNS
605                              "from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
606                              " where %s and (%s)"
607                              " %s"
608                              " order by %s limit %d, %d",
609                              which, myfilter, groupBy, order, args.start, args.requested);
610        DPRINTF(E_DEBUG, L_TIVO, "%s\n", sql);
611        ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
612        sqlite3_free(sql);
613        if( ret != SQLITE_OK )
614        {
615                DPRINTF(E_ERROR, L_HTTP, "SQL error: %s\n", zErrMsg);
616                sqlite3_free(zErrMsg);
617                Send500(h);
618                free(title);
619                free(which);
620                free(resp);
621                return;
622        }
623        strcatf(&str, "</TiVoContainer>");
624
625        ret = sprintf(str_buf, "<?xml version='1.0' encoding='UTF-8' ?>\n"
626                               "<TiVoContainer>"
627                                 "<Details>"
628                                   "<ContentType>x-container/tivo-%s</ContentType>"
629                                   "<SourceFormat>x-container/folder</SourceFormat>"
630                                   "<TotalItems>%d</TotalItems>"
631                                   "<Title>%s</Title>"
632                                 "</Details>"
633                                 "<ItemStart>%d</ItemStart>"
634                                 "<ItemCount>%d</ItemCount>",
635                                 type, totalMatches, title, args.start, args.returned);
636        str.data -= ret;
637        memcpy(str.data, &str_buf, ret);
638        str.size = str.off+ret;
639        free(title);
640        free(which);
641        BuildResp_upnphttp(h, str.data, str.size);
642        free(resp);
643        SendResp_upnphttp(h);
644}
645
646void
647ProcessTiVoCommand(struct upnphttp * h, const char * orig_path)
648{
649        char *path;
650        char *key, *val;
651        char *saveptr = NULL, *item;
652        char *command = NULL, *container = NULL, *anchorItem = NULL;
653        char *sortOrder = NULL, *filter = NULL;
654        sqlite_int64 detailItem=0;
655        int itemStart=0, itemCount=-100, anchorOffset=0, recurse=0;
656        unsigned long int randomSeed=0;
657
658        path = strdup(orig_path);
659        DPRINTF(E_DEBUG, L_GENERAL, "Processing TiVo command %s\n", path);
660
661        item = strtok_r( path, "&", &saveptr );
662        while( item != NULL )
663        {
664                if( *item == '\0' )
665                {
666                        item = strtok_r( NULL, "&", &saveptr );
667                        continue;
668                }
669                decodeString(item, 1);
670                val = item;
671                key = strsep(&val, "=");
672                decodeString(val, 1);
673                DPRINTF(E_DEBUG, L_GENERAL, "%s: %s\n", key, val);
674                if( strcasecmp(key, "Command") == 0 )
675                {
676                        command = val;
677                }
678                else if( strcasecmp(key, "Container") == 0 )
679                {
680                        container = val;
681                }
682                else if( strcasecmp(key, "ItemStart") == 0 )
683                {
684                        itemStart = atoi(val);
685                }
686                else if( strcasecmp(key, "ItemCount") == 0 )
687                {
688                        itemCount = atoi(val);
689                }
690                else if( strcasecmp(key, "AnchorItem") == 0 )
691                {
692                        anchorItem = basename(val);
693                }
694                else if( strcasecmp(key, "AnchorOffset") == 0 )
695                {
696                        anchorOffset = atoi(val);
697                }
698                else if( strcasecmp(key, "Recurse") == 0 )
699                {
700                        recurse = strcasecmp("yes", val) == 0 ? 1 : 0;
701                }
702                else if( strcasecmp(key, "SortOrder") == 0 )
703                {
704                        sortOrder = val;
705                }
706                else if( strcasecmp(key, "Filter") == 0 )
707                {
708                        filter = val;
709                }
710                else if( strcasecmp(key, "RandomSeed") == 0 )
711                {
712                        randomSeed = strtoul(val, NULL, 10);
713                }
714                else if( strcasecmp(key, "Url") == 0 )
715                {
716                        if( val )
717                                detailItem = strtoll(basename(val), NULL, 10);
718                }
719                else if( strcasecmp(key, "Format") == 0 || // Only send XML
720                         strcasecmp(key, "SerialNum") == 0 || // Unused for now
721                         strcasecmp(key, "DoGenres") == 0 ) // Not sure what this is, so ignore it
722                {
723                        ;;
724                }
725                else
726                {
727                        DPRINTF(E_DEBUG, L_GENERAL, "Unhandled parameter [%s]\n", key);
728                }
729                item = strtok_r( NULL, "&", &saveptr );
730        }
731        if( anchorItem )
732        {
733                strip_ext(anchorItem);
734        }
735
736        if( command )
737        {
738                if( strcmp(command, "QueryContainer") == 0 )
739                {
740                        if( !container || (strcmp(container, "/") == 0) )
741                        {
742                                SendRootContainer(h);
743                        }
744                        else
745                        {
746                                SendContainer(h, container, itemStart, itemCount, anchorItem, anchorOffset, recurse, sortOrder, filter, randomSeed);
747                        }
748                }
749                else if( strcmp(command, "QueryItem") == 0 )
750                {
751                        SendItemDetails(h, detailItem);
752                }
753                else
754                {
755                        DPRINTF(E_DEBUG, L_GENERAL, "Unhandled command [%s]\n", command);
756                        Send501(h);
757                        free(path);
758                        return;
759                }
760        }
761        free(path);
762        CloseSocket_upnphttp(h);
763}
764#endif // TIVO_SUPPORT
Note: See TracBrowser for help on using the repository browser.