[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.5

1.5     ! espie       1: /* $OpenBSD: cddb.c,v 1.4 2002/04/18 22:17:04 espie 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:
                     27: #include <sys/types.h>
                     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)
                     82:                strcpy(hostname, "unknown");
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 {
        !           109:                char *n = malloc(strlen(*p) + strlen(copy_buffer) + 1);
        !           110:                if (n == NULL)
        !           111:                        return;
        !           112:                strcpy(n, *p);
        !           113:                strcat(n, copy_buffer);
        !           114:                free(*p);
        !           115:                *p = n;
        !           116:        }
1.1       espie     117: }
                    118:
                    119: int
                    120: further_query(FILE *cout, char *line)
                    121: {
                    122:        char *key;
                    123:        char *title;
                    124:
                    125:        key = strchr(line, ' ');
                    126:        if (!key)
                    127:                return 0;
                    128:        *key++ = 0;
                    129:        title = strchr(key, ' ');
                    130:        if (!title)
                    131:                return 0;
                    132:        *title++ = 0;
                    133:        strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
                    134:        printf("%s", copy_buffer);
                    135:        strnvis(copy_buffer, line, MAXSIZE-1, VIS_TAB|VIS_NL);
                    136:        printf("(%s)\n", copy_buffer);
                    137:        fprintf(cout, "CDDB READ %s %s\r\n", line, key);
                    138:        fflush(cout);
                    139:        return 1;
                    140: }
                    141:
                    142:
                    143: int
                    144: connect_to(const char *host, const char *serv)
                    145: {
                    146:        int s = -1;
                    147:        struct addrinfo hints, *res0 = NULL, *res;
                    148:        int error;
                    149:
                    150:        memset(&hints, 0, sizeof hints);
                    151:        hints.ai_family = PF_UNSPEC;
                    152:        hints.ai_socktype = SOCK_STREAM;
                    153:
                    154:        error = getaddrinfo(host, serv, &hints, &res0);
                    155:        if (error) {
                    156:                warnx("%s", gai_strerror(error));
                    157:                return -1;
                    158:        }
                    159:
                    160:        for (res = res0; res; res = res->ai_next) {
                    161:                s = socket(res->ai_family, res->ai_socktype,
                    162:                    res->ai_protocol);
                    163:                if (s == -1)
                    164:                        continue;
                    165:                if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
                    166:                        close(s);
                    167:                        s = -1;
                    168:                        continue;
                    169:                }
                    170:                break;
                    171:        }
                    172:        if (s == -1)
                    173:                warn("cddb");
                    174:        freeaddrinfo(res0);
                    175:        return s;
                    176: }
                    177:
                    178: int
                    179: parse_connect_to(const char *host_port, const char *port)
                    180: {
                    181:        int s;
                    182:        char *last, *host;
                    183:
                    184:        host = (char *)host_port;
                    185:
                    186:        last = strrchr(host_port, ':');
                    187:        if (last != 0 && !(last != host && last[-1] == ':')) {
                    188:                port = last + 1;
                    189:                host = malloc(last - host_port + 1);
                    190:                if (!host)
                    191:                        return -1;
                    192:                memcpy(host, host_port, last-host_port);
                    193:                host[last-host_port] = 0;
                    194:        }
                    195:        s = connect_to(host, port);
                    196:        if (host != host_port)
                    197:                free(host);
                    198:        return s;
                    199: }
                    200:
                    201: char *
                    202: get_line(FILE *cin)
                    203: {
                    204:        char *line;
                    205:        size_t len;
                    206:
                    207:        line = fgetln(cin, &len);
                    208:        if (!line)
                    209:                return NULL;
                    210:        if (len == 0)
                    211:                return NULL;
                    212:        if (line[len-1] == '\n')
                    213:                line[--len] = 0;
                    214:        if (len != 0 && line[len-1] == '\r')
                    215:                line[--len] = 0;
                    216:        return line;
                    217: }
                    218:
                    219: char *
                    220: get_answer(FILE *cin)
                    221: {
                    222:        char *line;
                    223:
                    224:        line = get_line(cin);
                    225:        if (*line != '2')
                    226:                return NULL;
                    227:        else
                    228:                return line;
                    229: }
                    230:
                    231: void
                    232: verify_track_names(char **names, int n, struct cd_toc_entry *e)
                    233: {
                    234:        int i;
                    235:
                    236:        for (i = 0; i < n; i++) {
                    237:                if (names[i] == 0)
                    238:                        names[i] = strdup(e->control & 4 ? "data" : "audio");
                    239:        }
                    240: }
                    241:
1.3       espie     242: char **
1.1       espie     243: cddb(const char *host_port, int n, struct cd_toc_entry *e, char *arg)
                    244: {
                    245:        int s = -1;
                    246:        FILE *cin = NULL;
                    247:        FILE *cout = NULL;
                    248:        char *type;
                    249:        char *line;
                    250:        char **result = NULL;
                    251:        int i;
                    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) {
                    297:                int number = atoi(arg);
                    298:                if (number == 0) {
                    299:                        if (strcmp(line, "211") == 0)
                    300:                                printf("cddb: multiple matches\n");
                    301:                        else {
                    302:                                printf("cddb: inexact match\n");
                    303:                                number = 1;
                    304:                        }
                    305:                }
                    306:                if (number == 0) {
                    307:                        for (i = 1;; i++) {
                    308:                                line = get_line(cin);
                    309:                                if (strcmp(line, ".") == 0)
                    310:                                        goto end;
                    311:                                printf("%d: %s\n", i, line);
                    312:                        }
                    313:                } else {
                    314:                        int ok = 0;
                    315:
                    316:                        for (i = 1;; i++) {
                    317:                                line = get_line(cin);
                    318:                                if (!line)
                    319:                                        break;
                    320:                                if (strcmp(line, ".") == 0)
                    321:                                        break;
                    322:                                if (i == number)
                    323:                                        ok = further_query(cout, line);
                    324:                        }
                    325:                        if (!ok)
                    326:                                goto end;
                    327:                }
                    328:        } else if (strcmp(line, "200") != 0 || !further_query(cout, type))
                    329:                goto end;
                    330:        result = malloc(sizeof(char *) * n+1);
                    331:        if (!result)
                    332:                goto end;
                    333:        for (i = 0; i <= n; i++)
                    334:                result[i] = NULL;
                    335:        line = get_answer(cin);
                    336:        if (!line)
                    337:                goto end2;
                    338:        for (;;) {
                    339:                long k;
                    340:                char *end;
                    341:
                    342:                line = get_line(cin);
                    343:                if (!line)
                    344:                        goto end2;
                    345:                if (strcmp(line, ".") == 0)
                    346:                        goto end;
                    347:                if (strncmp(line, "TTITLE", 6) != 0)
                    348:                        continue;
                    349:                line += 6;
                    350:                k = strtol(line, &end, 10);
                    351:                if (*end++ != '=')
                    352:                        continue;
                    353:                if (k >= n)
                    354:                        continue;
1.5     ! espie     355:                safe_copy(&result[k], end);
1.1       espie     356:        }
                    357:        fprintf(cout, "QUIT\r\n");
                    358:        verify_track_names(result, n, e);
                    359:        goto end;
                    360: end2:
                    361:        free(result);
                    362:        result = NULL;
                    363: end:
                    364:        if (cout)
1.2       deraadt   365:                fclose(cout);
1.1       espie     366:        if (cin)
1.2       deraadt   367:                fclose(cin);
1.1       espie     368:        if (s != -1)
1.2       deraadt   369:                close(s);
1.1       espie     370:        return result;
                    371: }
                    372:
                    373: void
                    374: free_names(char **names)
                    375: {
                    376:        int i;
                    377:
                    378:        for (i = 0; names[i]; i++)
                    379:                free(names[i]);
                    380:        free(names);
                    381: }