[BACK]Return to cddb.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cdio

Annotation of src/usr.bin/cdio/cddb.c, Revision 1.13

1.13    ! deraadt     1: /* $OpenBSD: cddb.c,v 1.12 2007/05/01 01:26:12 jdixon Exp $ */
1.1       espie       2: /*
                      3:  * Copyright (c) 2002 Marc Espie.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
                     15:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     16:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     17:  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
                     18:  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     19:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     20:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     21:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     22:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     23:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     24:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
1.11      millert    27: #include <sys/param.h>
1.1       espie      28: #include <sys/socket.h>
                     29: #include <netinet/in.h>
                     30: #include <sys/cdio.h>
                     31: #include <err.h>
                     32: #include <netdb.h>
                     33: #include <stdio.h>
                     34: #include <stdlib.h>
                     35: #include <string.h>
                     36: #include <unistd.h>
                     37: #include <vis.h>
                     38: #include "extern.h"
                     39:
1.3       espie      40: unsigned long  cddb_sum(unsigned long);
                     41: void           send_hello(FILE *);
                     42: void           send_query(FILE *, int, struct cd_toc_entry *);
                     43: int            further_query(FILE *, char *);
                     44: int            connect_to(const char *, const char *);
                     45: int            parse_connect_to(const char *, const char *);
                     46: char *         get_line(FILE *);
1.1       espie      47: char *         get_answer(FILE *);
1.3       espie      48: void           verify_track_names(char **, int, struct cd_toc_entry *);
1.5       espie      49: void           safe_copy(char **, const char *);
1.1       espie      50:
                     51: unsigned long
                     52: cddb_sum(unsigned long v)
                     53: {
                     54:        unsigned long sum = 0;
                     55:
                     56:        while (v > 0) {
                     57:                sum += v % 10;
                     58:                v /= 10;
                     59:        }
                     60:        return (sum);
                     61: }
                     62:
1.3       espie      63: unsigned long
1.1       espie      64: cddb_discid(int n, struct cd_toc_entry *e)
                     65: {
                     66:        unsigned long sum;
                     67:        int i;
                     68:
                     69:        sum = 0;
1.3       espie      70:        for (i =0; i < n; i++)
1.1       espie      71:                sum += cddb_sum(entry2time(e+i));
1.3       espie      72:        return (((sum % 0xff) << 24) |
1.1       espie      73:            ((entry2time(e+n) - entry2time(e)) << 8) | n);
                     74: }
                     75:
                     76: void
                     77: send_hello(FILE *cout)
                     78: {
                     79:        char hostname[MAXHOSTNAMELEN];
                     80:
                     81:        if (gethostname(hostname, sizeof(hostname)) == -1)
1.6       deraadt    82:                strlcpy(hostname, "unknown", sizeof hostname);
1.3       espie      83:        fprintf(cout, "CDDB HELLO %s %s cdio " VERSION "\r\n",
1.1       espie      84:            getlogin(), hostname);
                     85:        fflush(cout);
                     86: }
                     87:
1.3       espie      88: void
1.1       espie      89: send_query(FILE *f, int n, struct cd_toc_entry *e)
                     90: {
                     91:        int i;
                     92:
                     93:        fprintf(f, "cddb query %8lx %d", cddb_discid(n, e), n);
                     94:        for (i = 0; i < n; i++)
                     95:                fprintf(f, " %lu", entry2frames(e+i));
                     96:        fprintf(f, " %lu\r\n", (entry2frames(e+n)-entry2frames(e)) /75);
                     97: }
                     98:
                     99: #define MAXSIZE 256
                    100: char copy_buffer[MAXSIZE];
                    101:
1.5       espie     102: void
                    103: safe_copy(char **p, const char *title)
1.1       espie     104: {
                    105:        strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
1.5       espie     106:        if (*p == NULL)
                    107:                *p = strdup(copy_buffer);
                    108:        else {
1.9       deraadt   109:                char *n;
                    110:
                    111:                if (asprintf(&n, "%s%s", *p, copy_buffer) == -1)
1.5       espie     112:                        return;
                    113:                free(*p);
                    114:                *p = n;
                    115:        }
1.1       espie     116: }
                    117:
                    118: int
                    119: further_query(FILE *cout, char *line)
                    120: {
                    121:        char *key;
                    122:        char *title;
                    123:
                    124:        key = strchr(line, ' ');
                    125:        if (!key)
                    126:                return 0;
                    127:        *key++ = 0;
                    128:        title = strchr(key, ' ');
                    129:        if (!title)
                    130:                return 0;
                    131:        *title++ = 0;
                    132:        strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
                    133:        printf("%s", copy_buffer);
                    134:        strnvis(copy_buffer, line, MAXSIZE-1, VIS_TAB|VIS_NL);
                    135:        printf("(%s)\n", copy_buffer);
                    136:        fprintf(cout, "CDDB READ %s %s\r\n", line, key);
                    137:        fflush(cout);
                    138:        return 1;
                    139: }
                    140:
                    141:
                    142: int
                    143: connect_to(const char *host, const char *serv)
                    144: {
                    145:        int s = -1;
                    146:        struct addrinfo hints, *res0 = NULL, *res;
                    147:        int error;
                    148:
                    149:        memset(&hints, 0, sizeof hints);
                    150:        hints.ai_family = PF_UNSPEC;
                    151:        hints.ai_socktype = SOCK_STREAM;
                    152:
                    153:        error = getaddrinfo(host, serv, &hints, &res0);
                    154:        if (error) {
                    155:                warnx("%s", gai_strerror(error));
                    156:                return -1;
                    157:        }
                    158:
                    159:        for (res = res0; res; res = res->ai_next) {
                    160:                s = socket(res->ai_family, res->ai_socktype,
                    161:                    res->ai_protocol);
                    162:                if (s == -1)
                    163:                        continue;
                    164:                if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
                    165:                        close(s);
                    166:                        s = -1;
                    167:                        continue;
                    168:                }
                    169:                break;
                    170:        }
                    171:        if (s == -1)
                    172:                warn("cddb");
                    173:        freeaddrinfo(res0);
                    174:        return s;
                    175: }
                    176:
                    177: int
                    178: parse_connect_to(const char *host_port, const char *port)
                    179: {
                    180:        int s;
                    181:        char *last, *host;
                    182:
                    183:        host = (char *)host_port;
                    184:
                    185:        last = strrchr(host_port, ':');
                    186:        if (last != 0 && !(last != host && last[-1] == ':')) {
                    187:                port = last + 1;
                    188:                host = malloc(last - host_port + 1);
                    189:                if (!host)
                    190:                        return -1;
                    191:                memcpy(host, host_port, last-host_port);
                    192:                host[last-host_port] = 0;
                    193:        }
                    194:        s = connect_to(host, port);
                    195:        if (host != host_port)
                    196:                free(host);
                    197:        return s;
                    198: }
                    199:
                    200: char *
                    201: get_line(FILE *cin)
                    202: {
                    203:        char *line;
                    204:        size_t len;
                    205:
                    206:        line = fgetln(cin, &len);
                    207:        if (!line)
                    208:                return NULL;
                    209:        if (len == 0)
                    210:                return NULL;
                    211:        if (line[len-1] == '\n')
                    212:                line[--len] = 0;
                    213:        if (len != 0 && line[len-1] == '\r')
                    214:                line[--len] = 0;
                    215:        return line;
                    216: }
                    217:
                    218: char *
                    219: get_answer(FILE *cin)
                    220: {
                    221:        char *line;
                    222:
                    223:        line = get_line(cin);
1.8       espie     224:        if (!line || *line != '2')
1.1       espie     225:                return NULL;
                    226:        else
                    227:                return line;
                    228: }
                    229:
                    230: void
                    231: verify_track_names(char **names, int n, struct cd_toc_entry *e)
                    232: {
                    233:        int i;
                    234:
                    235:        for (i = 0; i < n; i++) {
                    236:                if (names[i] == 0)
                    237:                        names[i] = strdup(e->control & 4 ? "data" : "audio");
                    238:        }
                    239: }
                    240:
1.3       espie     241: char **
1.1       espie     242: cddb(const char *host_port, int n, struct cd_toc_entry *e, char *arg)
                    243: {
                    244:        int s = -1;
                    245:        FILE *cin = NULL;
                    246:        FILE *cout = NULL;
                    247:        char *type;
                    248:        char *line;
                    249:        char **result = NULL;
                    250:        int i;
1.12      jdixon    251:        const char *errstr;
1.1       espie     252:
                    253:        s = parse_connect_to(host_port, "cddb");
                    254:        if (s == -1)
                    255:                goto end;
                    256:        cin = fdopen(s, "r");
                    257:        if (!cin) {
                    258:                warn("cddb: fdopen");
                    259:                goto end;
                    260:        }
                    261:        cout = fdopen(s, "w");
                    262:        s = -1;
                    263:        if (!cout) {
                    264:                warn("cddb: fdopen");
                    265:                goto end;
                    266:        }
                    267:        line = get_answer(cin);
                    268:        if (!line) {
                    269:                warnx("cddb: won't talk to us");
                    270:                goto end;
                    271:        }
                    272:
                    273:        send_hello(cout);
                    274:        line = get_answer(cin);
                    275:        if (!line) {
                    276:                warnx("cddb: problem in hello");
                    277:                goto end;
                    278:        }
                    279:
                    280:        send_query(cout, n, e);
                    281:        fflush(cout);
                    282:        line = get_answer(cin);
                    283:        if (!line) {
                    284:                warnx("cddb: problem in query");
                    285:                goto end;
                    286:        }
                    287:        type = strchr(line, ' ');
                    288:        if (!type)
                    289:                goto end;
                    290:        *type++ = 0;
                    291:        /* no match or other issue */
                    292:        if (strcmp(line, "202") == 0) {
                    293:                printf("cddb: No match in database\n");
                    294:                goto end;
                    295:        }
                    296:        if (strcmp(line, "211") == 0 || strcmp(line, "212") == 0) {
1.12      jdixon    297:                int number = strtonum(arg, 0, INT_MAX, &errstr);
                    298:                if (errstr != NULL)
                    299:                        errx(1, "%s: %s", errstr, arg);
1.1       espie     300:                if (number == 0) {
                    301:                        if (strcmp(line, "211") == 0)
                    302:                                printf("cddb: multiple matches\n");
                    303:                        else {
                    304:                                printf("cddb: inexact match\n");
                    305:                                number = 1;
                    306:                        }
                    307:                }
                    308:                if (number == 0) {
                    309:                        for (i = 1;; i++) {
                    310:                                line = get_line(cin);
1.8       espie     311:                                if (!line || strcmp(line, ".") == 0)
1.1       espie     312:                                        goto end;
                    313:                                printf("%d: %s\n", i, line);
                    314:                        }
                    315:                } else {
                    316:                        int ok = 0;
                    317:
                    318:                        for (i = 1;; i++) {
                    319:                                line = get_line(cin);
                    320:                                if (!line)
                    321:                                        break;
                    322:                                if (strcmp(line, ".") == 0)
                    323:                                        break;
                    324:                                if (i == number)
                    325:                                        ok = further_query(cout, line);
                    326:                        }
                    327:                        if (!ok)
                    328:                                goto end;
                    329:                }
                    330:        } else if (strcmp(line, "200") != 0 || !further_query(cout, type))
                    331:                goto end;
1.13    ! deraadt   332:        result = calloc(sizeof(char *), n + 1);
1.1       espie     333:        if (!result)
                    334:                goto end;
                    335:        for (i = 0; i <= n; i++)
                    336:                result[i] = NULL;
                    337:        line = get_answer(cin);
                    338:        if (!line)
                    339:                goto end2;
                    340:        for (;;) {
                    341:                long k;
                    342:                char *end;
                    343:
                    344:                line = get_line(cin);
                    345:                if (!line)
                    346:                        goto end2;
                    347:                if (strcmp(line, ".") == 0)
                    348:                        goto end;
                    349:                if (strncmp(line, "TTITLE", 6) != 0)
                    350:                        continue;
                    351:                line += 6;
                    352:                k = strtol(line, &end, 10);
                    353:                if (*end++ != '=')
                    354:                        continue;
                    355:                if (k >= n)
                    356:                        continue;
1.5       espie     357:                safe_copy(&result[k], end);
1.1       espie     358:        }
                    359:        fprintf(cout, "QUIT\r\n");
                    360:        verify_track_names(result, n, e);
                    361:        goto end;
                    362: end2:
                    363:        free(result);
                    364:        result = NULL;
                    365: end:
                    366:        if (cout)
1.2       deraadt   367:                fclose(cout);
1.1       espie     368:        if (cin)
1.2       deraadt   369:                fclose(cin);
1.1       espie     370:        if (s != -1)
1.2       deraadt   371:                close(s);
1.1       espie     372:        return result;
                    373: }
                    374:
                    375: void
                    376: free_names(char **names)
                    377: {
                    378:        int i;
                    379:
                    380:        for (i = 0; names[i]; i++)
                    381:                free(names[i]);
                    382:        free(names);
                    383: }