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

1.1       espie       1: /* $OpenBSD $*/
                      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:
                     40: unsigned long  cddb_discid(int, struct cd_toc_entry *);
                     41: unsigned long  cddb_sum(unsigned long);
                     42: void           send_hello(FILE *);
                     43: void           send_query(FILE *, int, struct cd_toc_entry *);
                     44: int            further_query(FILE *, char *);
                     45: int            connect_to(const char *, const char *);
                     46: int            parse_connect_to(const char *, const char *);
                     47: char *                 get_line(FILE *);
                     48: char *         get_answer(FILE *);
                     49: void           verify_track_names(char **, int, struct cd_toc_entry *);
                     50: char *                 safe_copy(const char *);
                     51:
                     52: unsigned long
                     53: cddb_sum(unsigned long v)
                     54: {
                     55:        unsigned long sum = 0;
                     56:
                     57:        while (v > 0) {
                     58:                sum += v % 10;
                     59:                v /= 10;
                     60:        }
                     61:        return (sum);
                     62: }
                     63:
                     64: unsigned long
                     65: cddb_discid(int n, struct cd_toc_entry *e)
                     66: {
                     67:        unsigned long sum;
                     68:        int i;
                     69:
                     70:        sum = 0;
                     71:        for (i =0; i < n; i++)
                     72:                sum += cddb_sum(entry2time(e+i));
                     73:        return (((sum % 0xff) << 24) |
                     74:            ((entry2time(e+n) - entry2time(e)) << 8) | n);
                     75: }
                     76:
                     77: void
                     78: send_hello(FILE *cout)
                     79: {
                     80:        char hostname[MAXHOSTNAMELEN];
                     81:
                     82:        if (gethostname(hostname, sizeof(hostname)) == -1)
                     83:                strcpy(hostname, "unknown");
                     84:        fprintf(cout, "CDDB HELLO %s %s cdio " VERSION "\r\n",
                     85:            getlogin(), hostname);
                     86:        fflush(cout);
                     87: }
                     88:
                     89: void
                     90: send_query(FILE *f, int n, struct cd_toc_entry *e)
                     91: {
                     92:        int i;
                     93:
                     94:        fprintf(f, "cddb query %8lx %d", cddb_discid(n, e), n);
                     95:        for (i = 0; i < n; i++)
                     96:                fprintf(f, " %lu", entry2frames(e+i));
                     97:        fprintf(f, " %lu\r\n", (entry2frames(e+n)-entry2frames(e)) /75);
                     98: }
                     99:
                    100: #define MAXSIZE 256
                    101: char copy_buffer[MAXSIZE];
                    102:
                    103: char *
                    104: safe_copy(const char *title)
                    105: {
                    106:        strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
                    107:        return strdup(copy_buffer);
                    108: }
                    109:
                    110: int
                    111: further_query(FILE *cout, char *line)
                    112: {
                    113:        char *key;
                    114:        char *title;
                    115:
                    116:        key = strchr(line, ' ');
                    117:        if (!key)
                    118:                return 0;
                    119:        *key++ = 0;
                    120:        title = strchr(key, ' ');
                    121:        if (!title)
                    122:                return 0;
                    123:        *title++ = 0;
                    124:        strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
                    125:        printf("%s", copy_buffer);
                    126:        strnvis(copy_buffer, line, MAXSIZE-1, VIS_TAB|VIS_NL);
                    127:        printf("(%s)\n", copy_buffer);
                    128:        fprintf(cout, "CDDB READ %s %s\r\n", line, key);
                    129:        fflush(cout);
                    130:        return 1;
                    131: }
                    132:
                    133:
                    134: int
                    135: connect_to(const char *host, const char *serv)
                    136: {
                    137:        int s = -1;
                    138:        struct addrinfo hints, *res0 = NULL, *res;
                    139:        int error;
                    140:
                    141:        memset(&hints, 0, sizeof hints);
                    142:        hints.ai_family = PF_UNSPEC;
                    143:        hints.ai_socktype = SOCK_STREAM;
                    144:
                    145:        error = getaddrinfo(host, serv, &hints, &res0);
                    146:        if (error) {
                    147:                warnx("%s", gai_strerror(error));
                    148:                return -1;
                    149:        }
                    150:
                    151:        for (res = res0; res; res = res->ai_next) {
                    152:                s = socket(res->ai_family, res->ai_socktype,
                    153:                    res->ai_protocol);
                    154:                if (s == -1)
                    155:                        continue;
                    156:                if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
                    157:                        close(s);
                    158:                        s = -1;
                    159:                        continue;
                    160:                }
                    161:                break;
                    162:        }
                    163:        if (s == -1)
                    164:                warn("cddb");
                    165:        freeaddrinfo(res0);
                    166:        return s;
                    167: }
                    168:
                    169: int
                    170: parse_connect_to(const char *host_port, const char *port)
                    171: {
                    172:        int s;
                    173:        char *last, *host;
                    174:
                    175:        host = (char *)host_port;
                    176:
                    177:        last = strrchr(host_port, ':');
                    178:        if (last != 0 && !(last != host && last[-1] == ':')) {
                    179:                port = last + 1;
                    180:                host = malloc(last - host_port + 1);
                    181:                if (!host)
                    182:                        return -1;
                    183:                memcpy(host, host_port, last-host_port);
                    184:                host[last-host_port] = 0;
                    185:        }
                    186:        s = connect_to(host, port);
                    187:        if (host != host_port)
                    188:                free(host);
                    189:        return s;
                    190: }
                    191:
                    192: char *
                    193: get_line(FILE *cin)
                    194: {
                    195:        char *line;
                    196:        size_t len;
                    197:
                    198:        line = fgetln(cin, &len);
                    199:        if (!line)
                    200:                return NULL;
                    201:        if (len == 0)
                    202:                return NULL;
                    203:        if (line[len-1] == '\n')
                    204:                line[--len] = 0;
                    205:        if (len != 0 && line[len-1] == '\r')
                    206:                line[--len] = 0;
                    207:        return line;
                    208: }
                    209:
                    210: char *
                    211: get_answer(FILE *cin)
                    212: {
                    213:        char *line;
                    214:
                    215:        line = get_line(cin);
                    216:        if (*line != '2')
                    217:                return NULL;
                    218:        else
                    219:                return line;
                    220: }
                    221:
                    222: void
                    223: verify_track_names(char **names, int n, struct cd_toc_entry *e)
                    224: {
                    225:        int i;
                    226:
                    227:        for (i = 0; i < n; i++) {
                    228:                if (names[i] == 0)
                    229:                        names[i] = strdup(e->control & 4 ? "data" : "audio");
                    230:        }
                    231: }
                    232:
                    233: char **
                    234: cddb(const char *host_port, int n, struct cd_toc_entry *e, char *arg)
                    235: {
                    236:        int s = -1;
                    237:        FILE *cin = NULL;
                    238:        FILE *cout = NULL;
                    239:        char *type;
                    240:        char *line;
                    241:        char **result = NULL;
                    242:        int i;
                    243:
                    244:        s = parse_connect_to(host_port, "cddb");
                    245:        if (s == -1)
                    246:                goto end;
                    247:        cin = fdopen(s, "r");
                    248:        if (!cin) {
                    249:                warn("cddb: fdopen");
                    250:                goto end;
                    251:        }
                    252:        cout = fdopen(s, "w");
                    253:        s = -1;
                    254:        if (!cout) {
                    255:                warn("cddb: fdopen");
                    256:                goto end;
                    257:        }
                    258:        line = get_answer(cin);
                    259:        if (!line) {
                    260:                warnx("cddb: won't talk to us");
                    261:                goto end;
                    262:        }
                    263:
                    264:        send_hello(cout);
                    265:        line = get_answer(cin);
                    266:        if (!line) {
                    267:                warnx("cddb: problem in hello");
                    268:                goto end;
                    269:        }
                    270:
                    271:        send_query(cout, n, e);
                    272:        fflush(cout);
                    273:        line = get_answer(cin);
                    274:        if (!line) {
                    275:                warnx("cddb: problem in query");
                    276:                goto end;
                    277:        }
                    278:        type = strchr(line, ' ');
                    279:        if (!type)
                    280:                goto end;
                    281:        *type++ = 0;
                    282:        /* no match or other issue */
                    283:        if (strcmp(line, "202") == 0) {
                    284:                printf("cddb: No match in database\n");
                    285:                goto end;
                    286:        }
                    287:        if (strcmp(line, "211") == 0 || strcmp(line, "212") == 0) {
                    288:                int number = atoi(arg);
                    289:                if (number == 0) {
                    290:                        if (strcmp(line, "211") == 0)
                    291:                                printf("cddb: multiple matches\n");
                    292:                        else {
                    293:                                printf("cddb: inexact match\n");
                    294:                                number = 1;
                    295:                        }
                    296:                }
                    297:                if (number == 0) {
                    298:                        for (i = 1;; i++) {
                    299:                                line = get_line(cin);
                    300:                                if (strcmp(line, ".") == 0)
                    301:                                        goto end;
                    302:                                printf("%d: %s\n", i, line);
                    303:                        }
                    304:                } else {
                    305:                        int ok = 0;
                    306:
                    307:                        for (i = 1;; i++) {
                    308:                                line = get_line(cin);
                    309:                                if (!line)
                    310:                                        break;
                    311:                                if (strcmp(line, ".") == 0)
                    312:                                        break;
                    313:                                if (i == number)
                    314:                                        ok = further_query(cout, line);
                    315:                        }
                    316:                        if (!ok)
                    317:                                goto end;
                    318:                }
                    319:        } else if (strcmp(line, "200") != 0 || !further_query(cout, type))
                    320:                goto end;
                    321:        result = malloc(sizeof(char *) * n+1);
                    322:        if (!result)
                    323:                goto end;
                    324:        for (i = 0; i <= n; i++)
                    325:                result[i] = NULL;
                    326:        line = get_answer(cin);
                    327:        if (!line)
                    328:                goto end2;
                    329:        for (;;) {
                    330:                long k;
                    331:                char *end;
                    332:
                    333:                line = get_line(cin);
                    334:                if (!line)
                    335:                        goto end2;
                    336:                if (strcmp(line, ".") == 0)
                    337:                        goto end;
                    338:                if (strncmp(line, "TTITLE", 6) != 0)
                    339:                        continue;
                    340:                line += 6;
                    341:                k = strtol(line, &end, 10);
                    342:                if (*end++ != '=')
                    343:                        continue;
                    344:                if (k >= n)
                    345:                        continue;
                    346:                result[k] = safe_copy(end);
                    347:        }
                    348:        fprintf(cout, "QUIT\r\n");
                    349:        verify_track_names(result, n, e);
                    350:        goto end;
                    351: end2:
                    352:        free(result);
                    353:        result = NULL;
                    354: end:
                    355:        if (cout)
1.2     ! deraadt   356:                fclose(cout);
1.1       espie     357:        if (cin)
1.2     ! deraadt   358:                fclose(cin);
1.1       espie     359:        if (s != -1)
1.2     ! deraadt   360:                close(s);
1.1       espie     361:        return result;
                    362: }
                    363:
                    364: void
                    365: free_names(char **names)
                    366: {
                    367:        int i;
                    368:
                    369:        for (i = 0; names[i]; i++)
                    370:                free(names[i]);
                    371:        free(names);
                    372: }