📄 cddbtool.c
字号:
/* cddb.c 31.5.99 tn stuff to access the cddb-database via the cddbp-protocol standalone version*/#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#if defined(linux) || defined(__CYGWIN32__)#include <getopt.h>#endif#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <gtk/gtk.h>#include <gdk/gdk.h>#include "xcdroast.h"#include "main.h"#ifndef INADDR_NONE#define INADDR_NONE 0xFFFFFFFF#endifgchar hostname[MAXLINE];gchar username[MAXLINE];cddb_match_t **cddbmatch;gint matchnr;gint oldtnr;/* extract the 3 digit code from a cddb-answer */gint get_cddb_code(gchar *line) {gchar tmp[MAXLINE]; if (line == NULL || strlen(line) < 3) { return 0; } strncpy(tmp,line,3); tmp[3] = '\0'; return(atoi(tmp));}/* connect to the cddb-server and return socket-fd: return -1 on "hostname lookup failure" -2 on "cant open stream socket" -3 on "connection refused" -4 on "no response from server" -5 on "timeout while connect"*/gint connect_cddb_server(gchar *server, gint port) {struct sockaddr_in serv_addr;struct hostent *myhost;gchar tmp[MAXLINE];gint sockfd,n; /* resolv ipnumber from hostname if neccessary */ if ((serv_addr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE) { /* no valid ip-nummer, look up name */ if ((myhost = gethostbyname(server)) == NULL) { return -1; } memcpy(&serv_addr.sin_addr, myhost->h_addr, myhost->h_length); } /* fill structure serv_addr */ serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); /* open tcp socket (internet stream socket) */ if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return -2; } /* connect */ if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { close(sockfd); return -3; } /* read connect response */ n = read_line2(sockfd, tmp, MAXLINE, 1); if (n == -2) { /* timeout */ close(sockfd); return -5; } if (n < 0) { g_print("-11: Error: read error on socket when connecting\n"); fflush(stdout); close(sockfd); return -4; } return sockfd;}/* perform cddbp-handshaking *//* return 0 on success, 1 on error */gint cddb_handshake(gint sockfd) {gchar tmp[MAXLINE];gint n, code; g_snprintf(tmp,MAXLINE,"cddb hello %s %s xcdroast %s", username,hostname,XCDROAST_VERSION); /* now send string */ if (writen(sockfd,tmp,strlen(tmp), 1) != strlen(tmp)) { g_print("-10: Error: write error on socket when cddb handshaking\n"); fflush(stdout); return 1; } /* read response */ n = read_line2(sockfd, tmp, MAXLINE, 1); if (n < 0) { g_print("-11: Error: read error on socket when cddb handshaking\n"); fflush(stdout); return 1; } code = get_cddb_code(tmp); switch(code) { /* all ok */ case 200: return 0; /* handshake failed */ case 431: return 1; /* alread shook hands */ case 402: return 0; default: return 1; }}/* extract a match of the cddb-query command */void extract_cddb_match(gchar *match, gint exact) {gchar *p1; /* allocate memory and free old */ if (cddbmatch[matchnr] != NULL) { g_free(cddbmatch[matchnr]->categ); g_free(cddbmatch[matchnr]->discid); g_free(cddbmatch[matchnr]->dtitle); g_free(cddbmatch[matchnr]); } cddbmatch[matchnr] = g_new0(cddb_match_t,1); cddbmatch[matchnr]->exact = exact; p1 = strtok(match," "); cddbmatch[matchnr]->categ = g_strdup(p1); p1 = strtok(NULL," "); cddbmatch[matchnr]->discid = g_strdup(p1); p1 = strtok(NULL,""); cddbmatch[matchnr]->dtitle = g_strdup(p1); matchnr++;}/* perform cddbp-query *//* return 0 on success, 1 on error */gint cddb_query(gint sockfd, gchar *querystring) {gchar tmp[MAXLINE];gint n, code; matchnr = 0; oldtnr = -1; /* construct query */ strcpy(tmp,querystring); /* now send string */ if (writen(sockfd,tmp,strlen(tmp), 1) != strlen(tmp)) { g_print("-10: Error: write error on socket when cddb query\n"); fflush(stdout); return 1; } /* read response */ n = read_line2(sockfd, tmp, MAXLINE, 1); if (n < 0) { g_print("-11: Error: read error on socket when cddb query\n"); fflush(stdout); return 1; } code = get_cddb_code(tmp); switch(code) { /* exact match */ case 200: extract_cddb_match(tmp+4,1); return 0; /* no match found */ case 202: return 0; /* Database entry is corrupt */ case 403: return 0; /* No handshake */ case 409: return 1; /* list of matches found */ case 210: case 211: { while (matchnr < MAXCDDB) { n = read_line2(sockfd, tmp, MAXLINE, 1); if (n < 0) { g_print("-11: Error: read error on socket when cddb query\n"); fflush(stdout); return 1; } if (tmp[0] == '.') { /* done with list */ return 0; } if (code == 210) { extract_cddb_match(tmp,1); } else { extract_cddb_match(tmp,0); } } } default: return 1; }}/* parse the received cddb-entry into info-structures *//* return 0 on success, 1 on error */gint parse_cddb_entry(gint sockfd) {gchar tmp[MAXLINE];gchar tmp2[MAXLINE];gchar *p1;gint n, tnr; while (1) { n = read_line2(sockfd, tmp, MAXLINE, 1); if (n < 0) { g_print("-11: Error: read error on socket when cddb read\n"); fflush(stdout); return 1; } /* end marker found */ if (tmp[0] == '.') { /* no more tracks, close old track */ g_print("\"\n"); fflush(stdout); return 0; } if (strncmp(tmp,"DTITLE",6) == 0) { p1 = strtok(tmp,"="); p1 = strtok(NULL,""); strcpy(tmp2,p1); strip_string(tmp2); g_print("07: \"%s\"\n", convert_escape(tmp2)); fflush(stdout); continue; } if (strncmp(tmp,"TTITLE",6) == 0) { strcpy(tmp2,tmp+6); p1 = strtok(tmp2,"="); tnr = atoi(p1); /* got a new track? close line of previous one */ if (oldtnr != -1 && oldtnr != tnr) { g_print("\"\n"); fflush(stdout); } p1 = strtok(NULL,""); strcpy(tmp,p1); strip_string(tmp); if (oldtnr != -1 && oldtnr == tnr) { /* continue old line */ g_print("%s", convert_escape(tmp)); } else { /* new track line (to be continue) */ g_print("08: \"%s", convert_escape(tmp)); } oldtnr = tnr; continue; } }}/* perform cddbp-read *//* return 0 on success, 1 on error */gint cddb_read(gint sockfd, gint nr) {gchar tmp[MAXLINE];gint n, code; if (cddbmatch[nr] == 0) { /* no such match */ return 1; } /* construct query */ g_snprintf(tmp,MAXLINE,"cddb read %s %s",cddbmatch[nr]->categ, cddbmatch[nr]->discid); /* now send string */ if (writen(sockfd,tmp,strlen(tmp), 1) != strlen(tmp)) { g_print("-10: Error: write error on socket when cddb read\n"); fflush(stdout); return 1; } /* read response */ n = read_line2(sockfd, tmp, MAXLINE, 1); if (n < 0) { g_print("-11: Error: read error on socket when cddb read\n"); fflush(stdout); return 1; } code = get_cddb_code(tmp); switch(code) { /* database entry follow */ case 210: parse_cddb_entry(sockfd); return 0; /* no entry found */ case 401: return 1; /* server error */ case 402: return 1; /* Database entry is corrupt */ case 403: return 1; /* No handshake */ case 409: return 1; /* Access limit exceeded, explanation follows */ case 417: { while (1) { n = read_line2(sockfd, tmp, MAXLINE, 1); if (n < 0) { g_print("-11: Error: read error on socket when cddb query\n"); fflush(stdout); return 1; } if (tmp[0] == '.') { /* done with list */ return 1; } /* output error-message line of server */ g_print("-12: Server: %s\n",tmp); fflush(stdout); } } default: return 1; }}/* perform cddbp-quit *//* return 0 on success, 1 on error */gint cddb_quit(gint sockfd) {gchar tmp[MAXLINE]; /* construct query */ strcpy(tmp,"quit"); /* now send string */ if (writen(sockfd,tmp,strlen(tmp), 1) != strlen(tmp)) { g_print("-10: Error: write error on socket when cddb quit\n"); fflush(stdout); return 1; } return 0;}/* close the socket when user canceled-out */void close_cddb(sock) { if (sock > 0) { close(sock); }}/* do the cddb-work and output info to keep user informed *//* return 1 on trouble, 0 if all ok */gint start_cddb_query(gint *sockpnt, gchar *host, gint port, gchar *querystring) {gint i;gint sock;gchar tmptmp[MAXLINE]; /* connect */ g_print("00: Connecting to %s:%d\n",host,port); fflush(stdout); sock = connect_cddb_server(host,port); *sockpnt = sock; if (sock < 0) { switch (sock) { case -1: /* lookup error */ g_print("-1: Error: Hostname lookup failure\n"); break; case -2: /* socket error */ g_print("-2: Error: Can't open stream socket\n"); break; case -3: /* connection refused */ g_print("-3: Error: Connection refused\n"); break; case -4: /* no response from server */ g_print("-4: Error: No response from server\n"); break; case -5: /* timeout */ g_print("-5: Error: No answer within timeout\n"); break; } fflush(stdout); return 1; } /* connect was ok, now send handshake */ g_print("01: Connect ok: Sending handshake\n"); fflush(stdout); if (cddb_handshake(sock) != 0) { g_print("-6: Handshake failed - No valid CDDB-server?\n"); fflush(stdout); return 1; } /* start query */ g_print("02: Sending CDDB-query\n"); fflush(stdout); if (cddb_query(sock, querystring) != 0) { g_print("-7: Error: CDDB-query failed\n"); fflush(stdout); return 1; } /* now the global match-structure contains all hits */ if (matchnr == 0) { /* no matches found */ g_print("03: No matches found - unknown CD\n"); fflush(stdout); /* all the user can do now is to cancel */ return 1; } else { /* output number of matches */ g_print("%% %d\n",matchnr); fflush(stdout); /* what type of matches */ if (cddbmatch[0]->exact == 0) { /* close */ g_print("04: Found %d close matches - Please select (enter number and press enter)\n", matchnr); fflush(stdout); } else { /* exact */ g_print("05: Found %d exact matches - Please select (enter number and press enter)\n", matchnr); fflush(stdout); } /* now add all matches to clist */ for (i = 0; i < matchnr; i++) { strcpy(tmptmp,cddbmatch[i]->dtitle); g_print("#%02d: \"%s\"\n", i, convert_escape(tmptmp)); } g_print("#--\n"); fflush(stdout); } /* so..now wait until the user select a match */ return 0;}/* user selected a match - fetch the corresponding data *//* return 1 on trouble, 0 if all ok */gint continue_cddb_query(gint sock, gint match) { /* get data only when user manually not forbid it */ if (match != -1) { g_print("06: Requesting data - Please wait\n"); fflush(stdout); /* get the data */ if (cddb_read(sock, match) != 0) { g_print("-8: Error: CDDB-read failed\n"); fflush(stdout); return 1; } } if (cddb_quit(sock) != 0) { g_print("-9: Warning: CDDB-logout failed\n"); fflush(stdout); return 1; } close_cddb(sock); return 0;}void usage(gchar *cmd) { g_print("Usage: %s [options] (Version: %s)\n",cmd, XCDROAST_VERSION); g_print("Options:\n"); g_print("\t-s <cddb-server>\n"); g_print("\t-p <cddb-port>\n"); g_print("\t-u <id username>\n"); g_print("\t-h <id hostname>\n"); g_print("\t-m <match nr> get info for this match number\n\t (Do not wait for user input - set to -1 for match list only)\n"); g_print("\t-q <cddb-query-string>\n");}gint main(gint argc, gchar **argv) {gint c;gchar server[MAXLINE];gchar selectbuffer[MAXLINE];gchar querystring[MAXLINE];gint port;gint ret, match;gint sock;gint automatch; /* do some defaults */ strcpy(server,"freedb.freedb.org"); port = 888; strcpy(username,"undef"); strcpy(hostname,"localhost"); strcpy(querystring, ""); automatch = -2; cddbmatch = g_new0(cddb_match_t *,MAXCDDB); while ((c = getopt(argc,argv,"s:p:u:h:q:m:")) != EOF) switch((gchar)c) { case 's': strncpy(server,optarg,MAXLINE); break; case 'u': strncpy(username,optarg,MAXLINE); break; case 'h': strncpy(hostname,optarg,MAXLINE); break; case 'q': strncpy(querystring,optarg,MAXLINE); break; case 'p': port = atoi(optarg); break; case 'm': automatch = atoi(optarg); break; default: usage(argv[0]); exit(-1); } /* any parameters at all given? */ if (strcmp(querystring,"") == 0) { usage(argv[0]); exit(-1); } ret = start_cddb_query(&sock, server, port, querystring); if (ret == 0) { /* ok, now let the user select an match */ if (automatch == -2) { read_line2(STDIN_FILENO, selectbuffer, MAXLINE, 0); match = atoi(selectbuffer); } else { match = automatch; } ret = continue_cddb_query(sock, match); if (ret != 0) { /* some error */ exit(1); } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -