📄 cddb.c
字号:
/* * cddb.c Copyright 1999-2003 Haavard Kvaalen <havardk@xmms.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "cddb.h"#include "http.h"#include "cdaudio.h"#include "cdinfo.h"#include <libxmms/util.h>#include <gtk/gtk.h>#include <stdarg.h>#include <dirent.h>#include <pthread.h>#include "xmms/i18n.h"static guint32 cached_id = 0;static GtkWidget *server_dialog, *server_clist;static GtkWidget *debug_window, *debug_clist;static GList *debug_messages = NULL;static GList *temp_messages = NULL;static pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER;static guint cddb_timeout_id;void configure_set_cddb_server(gchar *server);static void cddb_log(gchar *str, ...){ static GList *end_ptr = NULL; static gint message_num = 0; va_list args; char *text; va_start(args, str); text = g_strdup_vprintf(str, args); va_end(args); message_num++; debug_messages = g_list_prepend(debug_messages, text); if (!end_ptr) end_ptr = debug_messages; if (message_num > CDDB_LOG_MAX) { GList *temp; temp = g_list_previous(end_ptr); temp->next = NULL; g_free(end_ptr->data); g_list_free_1(end_ptr); end_ptr = temp; message_num--; } if (debug_window) { pthread_mutex_lock(&list_mutex); temp_messages = g_list_append(temp_messages, g_strdup(text)); pthread_mutex_unlock(&list_mutex); }}static gint cddb_sum(gint in){ gint retval = 0; while (in > 0) { retval += in % 10; in /= 10; } return retval;}guint32 cdda_cddb_compute_discid(cdda_disc_toc_t *info){ gint i; guint high = 0, low; for (i = info->first_track; i <= info->last_track; i++) high += cddb_sum(info->track[i].minute * 60 + info->track[i].second); low = (info->leadout.minute * 60 + info->leadout.second) - (info->track[info->first_track].minute * 60 + info->track[info->first_track].second); return ((high % 0xff) << 24 | low << 8 | (info->last_track - info->first_track + 1));}static char * cddb_generate_offset_string(cdda_disc_toc_t *info){ char *buffer; int i; buffer = g_malloc(info->last_track * 7 + 1); sprintf(buffer, "%d", LBA(info->track[info->first_track])); for (i = info->first_track + 1; i <= info->last_track; i++) sprintf(buffer, "%s+%d", buffer, LBA(info->track[i])); return buffer;}static gchar * cddb_generate_hello_string(void){ static char *buffer; if (buffer == NULL) { char *env, *client = NULL, *version = NULL, **strs = NULL; env = getenv("XMMS_CDDB_CLIENT_NAME"); if (env) { strs = g_strsplit(env, " ", 2); if (strs && strs[0] && strs[1]) { client = strs[0]; version = strs[1]; } } if (!client || !version) { client = PACKAGE; version = VERSION; } buffer = g_strdup_printf("&hello=nobody+localhost+%s+%s", client, version); if (strs) g_strfreev(strs); } return buffer;}static gint cddb_http_open_connection(gchar * server, gint port){ gint sock; gchar *status; if((sock = http_open_connection(server, 80)) == 0) status = "Failed"; else status = "Ok"; cddb_log("Connecting to CDDB-server %s: %s", server, status); return sock;}static gboolean cddb_query(gchar *server, cdda_disc_toc_t *info, cddb_disc_header_t *cddb_info){ /* * Query the cddb-server for the cd. * Returns the *real* diskid and category. */ gint sock; gchar *offsets, *getstr; gchar buffer[256]; gchar **response; gint i; if((sock = cddb_http_open_connection(server, 80)) == 0) return FALSE; offsets = cddb_generate_offset_string(info); cddb_log("Sending query-command. Disc ID: %08x", cdda_cddb_compute_discid(info)); getstr = g_strdup_printf( "GET /~cddb/cddb.cgi?cmd=cddb+query+%08x+%d+%s+%d%s&proto=%d HTTP/1.0\r\n\r\n", cdda_cddb_compute_discid(info), info->last_track - info->first_track + 1, offsets, (info->leadout.minute * 60 + info->leadout.second), cddb_generate_hello_string(), cdda_cfg.cddb_protocol_level); g_free(offsets); write(sock, getstr, strlen(getstr)); g_free(getstr); if (http_read_first_line(sock, buffer, 256) < 0) { http_close_connection(sock); return FALSE; } http_close_connection(sock); response = g_strsplit(buffer, " ", 4); cddb_log("Query response: %s", buffer); switch(strtol(response[0], NULL, 10)) { case 200: /* One exact match */ for (i = 0; i < 4; i++) { if (response[i] == NULL) { g_strfreev(response); return FALSE; } } cddb_info->category = g_strdup(response[1]); cddb_info->discid = strtoul(response[2], NULL, 16); break; default: /* FIXME: Handle other 2xx */ g_strfreev(response); return FALSE; } g_strfreev(response); return TRUE;}static gint cddb_check_protocol_level(gchar *server){ int level = 0, sock, n; char *str, buffer[256]; if((sock = cddb_http_open_connection(server, 80)) == 0) return 0; str = g_strdup_printf( "GET /~cddb/cddb.cgi?cmd=stat%s&proto=1 HTTP/1.0\r\n\r\n", cddb_generate_hello_string()); write(sock, str, strlen(str)); g_free(str); if ((n = http_read_first_line(sock, buffer, 256)) < 0 || atoi(buffer) != 210) { if (n > 0) cddb_log("Getting cddb protocol level failed: %s", buffer); else cddb_log("Getting cddb protocol level failed."); http_close_connection(sock); return 0; } while (http_read_line(sock, buffer, 256) >= 0) { g_strstrip(buffer); if (!strncmp(buffer, "max proto:", 10)) level = atoi(buffer + 10); if (!strcmp(buffer, ".")) break; } http_close_connection(sock); cddb_log("Getting cddb protocol level. Got level %d", level); return (MIN(level, CDDB_MAX_PROTOCOL_LEVEL));}#define BUF2SIZE (80*3)static gboolean cddb_read(gchar *server, cddb_disc_header_t *cddb_info, cdinfo_t *cdinfo){ gint sock; gchar *readstr; gchar buffer[256], buffer2[BUF2SIZE]; gchar *realstr, *temp; gint len, command, bufs; gint num, oldnum; if((sock = cddb_http_open_connection(server, 80)) == 0) return FALSE; cddb_log("Sending read-command. Disc ID: %08x. Category: %s", cddb_info->discid, cddb_info->category); readstr = g_strdup_printf( "GET /~cddb/cddb.cgi?cmd=cddb+read+%s+%08x%s&proto=%d HTTP/1.0\r\n\r\n", cddb_info->category, cddb_info->discid, cddb_generate_hello_string(), cdda_cfg.cddb_protocol_level); write(sock, readstr, strlen(readstr)); g_free(readstr); if (http_read_first_line(sock, buffer, 256) < 0) { http_close_connection(sock); return FALSE; } cddb_log("Read response: %s", buffer); command = 1; bufs = 0; oldnum = -1; do {/* fprintf(stderr,"%s\n",buffer); */ realstr = strchr(buffer, '='); if (buffer[0] == '#' || !realstr) continue; realstr++; len = strlen(realstr); switch (command) { case 1: if (!strncmp(buffer, "DISCID", 6)) break; command++; case 2: if (!strncmp(buffer, "DTITLE", 6)) { strncpy(buffer2 + bufs, realstr, BUF2SIZE - bufs); bufs += len; break; } if (bufs > 0) { buffer2[BUF2SIZE-1] = '\0'; if ((temp = strstr(buffer2, " / ")) != NULL) { cdda_cdinfo_cd_set(cdinfo, g_strdup(temp+3), g_strndup(buffer2, temp-buffer2)); } else cdda_cdinfo_cd_set(cdinfo, g_strdup(buffer2), g_strdup(buffer2)); bufs = 0; } command++; case 3: if (!strncmp(buffer, "TTITLE", 6)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -