/* * Humax EPG Tool * by af123, 2011 */ #include #include #include #include #include #include #include #include #include #include #include #include "lint.h" int debug = 0; const char *version = "1.0.2"; unsigned long sysopts = 0; unsigned long filterflags = 0; int syntax() { fprintf(stderr, "Humax EPG Tool v%s, by af123, 2011.\n\n", version); fprintf(stderr, "Syntax: epg [options] [filters] ...\n\n"); fprintf(stderr, " Options:\n" " -b Brief output.\n" " -d[level] Set debug level.\n" " -f Specify alternate EPG data file.\n" " -h Show help text.\n" " -p Parsable output.\n" "\n" ); fprintf(stderr, " Filters: (can be specified multiple times, all must be true)\n" " -C Show only events with this CRID.\n" " -D Show only selected descriptor type.\n" " -E Show only selected event.\n" " -R Show only events with this Series ID.\n" " -S Show only selected service.\n" " -T Show only selected content types.\n" " -@ Show only programmes at time.\n" "\n" ); fprintf(stderr, " Commands:\n" " dump Show a parsed summary of the EPG.\n" " dumpraw Show raw data from the EPG.\n" " sqldump Produce SQL statements from EPG data.\n" " now Show what is currently on.\n" " parse Parse the EPG, no output.\n" " search Search programme names for text.\n" " searchall " "Search programme names/descriptions for text.\n" ); fprintf(stderr, "\n"); return 0; } #define DECOMPRESS(str, len) \ if (*(str) == 0x1f) uncompress_epg(&(str), &(len)) void pass(struct epg *epg __attribute__((unused)), struct section *s __attribute__((unused)), struct data *d __attribute__((unused)), struct descriptor **ds __attribute__((unused)), void *var __attribute__((unused))) { /* Do nothing. */ } void dumpraw(struct epg *epg __attribute__((unused)), struct section *s, struct data *d, struct descriptor **ds, void *var __attribute__((unused))) { dump_section(s); dump_data(d); if (ds[PARSER_SHORT_EVENT]) dump_descriptor(ds[PARSER_SHORT_EVENT], 1); if (ds[PARSER_USER_DEFINED]) dump_descriptor(ds[PARSER_USER_DEFINED], 1); if (ds[PARSER_CONTENT]) dump_descriptor(ds[PARSER_CONTENT], 1); if (ds[PARSER_CRID_EVENT]) dump_descriptor(ds[PARSER_CRID_EVENT], 1); if (ds[PARSER_CRID_SERIES]) dump_descriptor(ds[PARSER_CRID_SERIES], 1); if (ds[PARSER_CRID_REC]) dump_descriptor(ds[PARSER_CRID_REC], 1); } /* Strings should all be safe now the huffman module is in place... */ #define safeprintf printf static char * sql_escape_len(unsigned int len, char *txt) { static char buf[0x1000]; char *p; unsigned int i; p = buf; for (i = 0; i < len && *txt; i++) { if (*txt == '\'') *p++ = '\\'; *p++ = *txt++; } *p = '\0'; return buf; } void sqldumpstart() { printf("create table if not exists epg\n"); printf("(\n"); printf("service_id bigint unsigned not null default 0,\n"); printf("event_id bigint unsigned not null default 0,\n"); printf("start datetime not null,\n"); printf("duration bigint unsigned not null,\n"); printf("name varchar(255),\n"); printf("text varchar(255),\n"); printf("warning varchar(255),\n"); printf("content_type bigint unsigned not null,\n"); printf("content varchar(255),\n"); printf("event_crid varchar(255),\n"); printf("series_crid varchar(255),\n"); printf("rec_crid varchar(255),\n"); printf("primary key (service_id, event_id),\n"); printf("index name (name),\n"); printf("index text (text)\n"); printf(") engine=innodb;\n"); printf("truncate epg;\n"); printf("set autocommit = 0;\n"); } void sqldumpend() { printf("commit;\n"); } void sqldump(struct epg *epg __attribute__((unused)), struct section *s, struct data *d, struct descriptor **ds, void *var __attribute__((unused))) { time_t tm; tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec); printf("replace into epg set \n"); printf(" service_id = %d,\n", s->service_id); printf(" event_id = %d,\n", d->event_id); printf(" start = %ld,\n", tm); printf(" duration = %d", d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec); if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d = ds[PARSER_SHORT_EVENT]; DECOMPRESS(d->content.d77.name, d->content.d77.namelen); DECOMPRESS(d->content.d77.text, d->content.d77.textlen); printf(",\n name = '%s'", sql_escape_len(d->content.d77.namelen, d->content.d77.name)); printf(",\n text = '%s'", sql_escape_len(d->content.d77.textlen, d->content.d77.text)); } if (ds[PARSER_USER_DEFINED]) { struct descriptor *d = ds[PARSER_USER_DEFINED]; DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen); printf(",\n warning = '%s'", sql_escape_len(d->content.d137.warninglen, d->content.d137.warning)); } if (ds[PARSER_CONTENT]) { printf(",\n content_type = %d", ds[PARSER_CONTENT]->content.d84.level1); printf(",\n content = '%s'", content_type(ds[PARSER_CONTENT])); } if (ds[PARSER_CRID_EVENT]) { struct descriptor *d = ds[PARSER_CRID_EVENT]; printf(",\n event_crid = '%.*s'", d->content.d118.crids[0].cridlen, d->content.d118.crids[0].crid); } if (ds[PARSER_CRID_SERIES]) { struct descriptor *d = ds[PARSER_CRID_SERIES]; printf(",\n series_crid = '%.*s'", d->content.d118.crids[0].cridlen, d->content.d118.crids[0].crid); } if (ds[PARSER_CRID_REC]) { struct descriptor *d = ds[PARSER_CRID_REC]; printf(",\n rec_crid = '%.*s'", d->content.d118.crids[0].cridlen, d->content.d118.crids[0].crid); } printf(";\n"); } void dump(struct epg *epg __attribute__((unused)), struct section *s, struct data *d, struct descriptor **ds, void *var __attribute__((unused))) { time_t tm; tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec); if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d77 = ds[PARSER_SHORT_EVENT]; DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen); DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen); } if (ds[PARSER_USER_DEFINED]) { struct descriptor *d = ds[PARSER_USER_DEFINED]; DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen); } if (sysopts & SYSOPT_PARSABLE) { /* service_id, event_id, start, duration, encrypted, name, text * warning, content code, content type, * event CRID, series CRID, rec CRID */ printf("%d\t%d\t%ld\t%d\t%d\t", s->service_id, d->event_id, tm, d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec, d->u1.u.free_CA_mode); if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d77 = ds[PARSER_SHORT_EVENT]; safeprintf("%.*s\t", d77->content.d77.namelen, d77->content.d77.name); safeprintf("%.*s\t", d77->content.d77.textlen, d77->content.d77.text); } else printf("\t\t"); if (ds[PARSER_USER_DEFINED]) { struct descriptor *d137 = ds[PARSER_USER_DEFINED]; safeprintf("%.*s\t", d137->content.d137.warninglen, d137->content.d137.warning); } else printf("\t"); if (ds[PARSER_CONTENT]) { printf("%d\t", ds[PARSER_CONTENT]->content.d84.level1); printf("%s\t", content_type(ds[PARSER_CONTENT])); } else printf("\t\t"); if (ds[PARSER_CRID_EVENT]) { struct descriptor *d = ds[PARSER_CRID_EVENT]; printf("%.*s\t", d->content.d118.crids[0].cridlen, d->content.d118.crids[0].crid); } else printf("\t"); if (ds[PARSER_CRID_SERIES]) { struct descriptor *d = ds[PARSER_CRID_SERIES]; printf("%.*s\t", d->content.d118.crids[0].cridlen, d->content.d118.crids[0].crid); } else printf("\t"); if (ds[PARSER_CRID_REC]) { struct descriptor *d = ds[PARSER_CRID_REC]; printf("%.*s\t", d->content.d118.crids[0].cridlen, d->content.d118.crids[0].crid); } else printf("\t"); printf("\n"); return; } printf("----------------------------------------------------------\n"); if (sysopts & SYSOPT_BRIEF) { safeprintf("%d/%d: %s+%d\n", s->service_id, d->event_id, ctime_nl(&tm), d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec); if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d77 = ds[PARSER_SHORT_EVENT]; safeprintf("Name:%.*s\n", d77->content.d77.namelen, d77->content.d77.name); safeprintf("Text:%.*s\n", d77->content.d77.textlen, d77->content.d77.text); } if (ds[PARSER_USER_DEFINED]) { struct descriptor *d137 = ds[PARSER_USER_DEFINED]; safeprintf("Warning:%.*s\n", d137->content.d137.warninglen, d137->content.d137.warning); } return; } printf("%30s: %d\n", "Service ID", s->service_id); printf("%30s: %d\n", "Event ID", d->event_id); printf("%30s: %#x %d:%02d:%02d (%s)\n", "start_date", d->start_date, d->start_hour, d->start_min, d->start_sec, ctime_nl(&tm)); printf("%30s: %d:%02d:%02d\n", "duration", d->dur_hour, d->dur_min, d->dur_sec); printf("%30s: %d\n", "encrypted", d->u1.u.free_CA_mode); if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d77 = ds[PARSER_SHORT_EVENT]; safeprintf("%30s: %.*s\n", "Name", d77->content.d77.namelen, d77->content.d77.name); safeprintf("%30s: %.*s\n", "Text", d77->content.d77.textlen, d77->content.d77.text); } if (ds[PARSER_USER_DEFINED]) { struct descriptor *d137 = ds[PARSER_USER_DEFINED]; safeprintf("%30s: %.*s\n", "Warning", d137->content.d137.warninglen, d137->content.d137.warning); } if (ds[PARSER_CONTENT]) printf("%30s: %s (%d)\n", "Content Type", content_type(ds[PARSER_CONTENT]), ds[PARSER_CONTENT]->content.d84.level1); if (ds[PARSER_CRID_EVENT]) printf("%30s: %.*s\n", "Event CRID", ds[PARSER_CRID_EVENT]->content.d118.crids[0].cridlen, ds[PARSER_CRID_EVENT]->content.d118.crids[0].crid); if (ds[PARSER_CRID_SERIES]) printf("%30s: %.*s\n", "Series CRID", ds[PARSER_CRID_SERIES]->content.d118.crids[0].cridlen, ds[PARSER_CRID_SERIES]->content.d118.crids[0].crid); if (ds[PARSER_CRID_REC]) { struct descriptor *d118 = ds[PARSER_CRID_REC]; int i; for (i = 0; i < d118->content.d118.i; i++) { struct crid *crid = &d118->content.d118.crids[i]; printf("%30s: %.*s\n", "Recommended CRID", crid->cridlen, crid->crid); } } } void search(struct epg *epg __attribute__((unused)), struct section *s, struct data *d, struct descriptor **ds, void *var) { if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d77 = ds[PARSER_SHORT_EVENT]; DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen); if (strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.name, (char *)var)) dump(epg, s, d, ds, NULL); } } void searchall(struct epg *epg __attribute__((unused)), struct section *s, struct data *d, struct descriptor **ds, void *var) { if (ds[PARSER_SHORT_EVENT]) { struct descriptor *d77 = ds[PARSER_SHORT_EVENT]; DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen); DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen); if (strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.name, (char *)var) || strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.text, (char *)var)) dump(epg, s, d, ds, NULL); } } #define GETOPTOPT \ do { \ if (*++cp == '\0' && argc > 1) \ { \ argc--, argv++; \ cp = argv[0]; \ } \ while (*cp != '\0' && isspace((int)*cp)) \ cp++; \ } while (0) #define GETOPTINTOPT \ do { \ if (*++cp == '\0' && argc > 1 && atoi(argv[1]) > 0) \ { \ argc--, argv++; \ cp = argv[0]; \ } \ while (*cp != '\0' && isspace((int)*cp)) \ cp++; \ } while (0) #define GETOPT \ do { \ if (*++cp == '\0' && argc < 2) \ { \ fprintf(stderr, \ "No argument supplied for -%c\n", opt); \ exit(1); \ } \ else if (*cp == '\0') \ { \ argc--, argv++; \ cp = argv[0]; \ } \ while (isspace((int)*cp)) \ cp++; \ } while (0) int main(int argc, char **argv) { char *epgpath = DEFAULT_EPG_FILE; struct epgfilter *filter = NULL; char *cp; argc--, argv++; while (argc > 0 && *argv[0] == '-') { for (cp = &argv[0][1]; *cp; cp++) { char opt; switch (opt = *cp) { case 'b': sysopts |= SYSOPT_BRIEF; break; case 'd': GETOPTINTOPT; if (*cp == '\0') debug = 1; else debug = atoi(cp); goto nextopt; case 'f': GETOPT; epgpath = strdup(cp); goto nextopt; case 'h': return syntax(); case 'p': sysopts |= SYSOPT_PARSABLE; break; /* Filters */ case '@': GETOPT; add_epgfilter(&filter, FILTER_TIMESTAMP, atoi(cp), 0, NULL, FT_EQUAL); goto nextopt; case 'C': GETOPT; add_epgfilter(&filter, FILTER_CRID, 0, 0, cp, FT_EQUAL); goto nextopt; case 'D': GETOPT; add_epgfilter(&filter, FILTER_DESCRIPTOR, atoi(cp), 0, NULL, FT_EQUAL); goto nextopt; case 'E': GETOPT; add_epgfilter(&filter, FILTER_EVENT, atoi(cp), 0, NULL, FT_EQUAL); goto nextopt; case 'S': GETOPT; add_epgfilter(&filter, FILTER_SERVICE, atoi(cp), 0, NULL, FT_EQUAL); goto nextopt; case 'R': GETOPT; add_epgfilter(&filter, FILTER_SCRID, 0, 0, cp, FT_EQUAL); goto nextopt; case 'T': GETOPT; add_epgfilter(&filter, FILTER_CONTENT, atoi(cp), 0, NULL, FT_EQUAL); goto nextopt; } } nextopt: argc--, argv++; } if (argc < 1) return syntax(); if (!strcmp(argv[0], "dump")) parse(epgpath, dump, NULL, filter); else if (!strcmp(argv[0], "parse")) parse(epgpath, pass, NULL, filter); else if (!strcmp(argv[0], "dumpraw")) parse(epgpath, dumpraw, NULL, filter); else if (!strcmp(argv[0], "sqldump")) { sqldumpstart(); parse(epgpath, sqldump, NULL, filter); sqldumpend(); } else if (!strcmp(argv[0], "now")) { time_t tm; time(&tm); add_epgfilter(&filter, FILTER_TIMESTAMP, tm, 0, NULL, FT_EQUAL); parse(epgpath, dump, NULL, filter); } else if (!strcmp(argv[0], "search") && argc > 1) parse(epgpath, search, (void *)argv[1], filter); else if (!strcmp(argv[0], "searchall") && argc > 1) parse(epgpath, searchall, (void *)argv[1], filter); else syntax(); return 0; }