/* save and transmit cddb-information Written by Matthias Hensler Copyright WSPse 1999+2000 eMail: wsp@gmx.de Created: 2000/02/28 Updated: 2000/03/20 */ /* Copying: This program is free software; you can redistribute it and/or modify it under the terms of the GNU Gerneral Public License as published by the Free Soft- ware Foundation; either version 2 of 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 MERCHANTABILTY 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include "mp3creat.h" #ifdef HAVE_DIRENT_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif /* fetch externals */ extern int track_last; extern struct { int min; int sec; int frame; } cdtoc[100]; extern int cddb_open_cddbp(char *addr); extern unsigned long cddb_discid(int tot_trks); extern void setup_stat_win(int max_length); extern void destroy_stat_win(); extern void print_stat_win(char *text); extern void popup_error_win(char *tx); extern void wuuush(int); extern void free_field_select(field_select_typ **anchor); extern int open_socket (const char *address); extern int read_from_sock(char **line, int sock_fd, BOOL wait); extern int write_to_sock(char *buf, int len, int sock_fd); extern field_select_typ *select_field_box(field_select_typ *fs_anchor, int max_length, char *stat_text, BOOL use_old, BOOL allow_space); extern int create_sub_dirs(char *filename, BOOL mode); extern char *copy_char_str(char *old); extern char *kill_double_slashs(char *string); extern BOOL select_yesno_box(char *tx); extern void free_char_array(char **array); extern BOOL config_cddb_enbl; extern const char *weekday[]; extern const char *month[]; extern char *cddb_genres; extern BOOL cddb_cddb_entry_is_clean; extern int cddb_cddb_entry_revision; extern char external_version_str[]; extern char *def_cddb_server; extern char *def_cddb_bank; extern char *def_tmp_file; extern char *def_cddb_email; extern char *def_smtp_server; extern char *def_my_email; #define SMTP_MAXLEN 512 int cddb_get_genre_list(char *addr) { int cddb_fd; char *inp_buf; char *pat; setup_stat_win(50); cddb_fd = cddb_open_cddbp(addr); if(cddb_fd < 0) { destroy_stat_win(); return 1; } print_stat_win(_("asking for categories")); if(write_to_sock("cddb lscat\r\n", 12, cddb_fd) != 0) { print_stat_win(_("failed")); close(cddb_fd); destroy_stat_win(); return 1; } if(read_from_sock(&inp_buf, cddb_fd, TRUE) != 0) { print_stat_win(_("failed")); close(cddb_fd); destroy_stat_win(); return 1; } if(strncmp(inp_buf, "210", 3) != 0) { print_stat_win(_("failed")); free(inp_buf); close(cddb_fd); destroy_stat_win(); return 1; } free(inp_buf); inp_buf = NULL; /* receive categories */ if(cddb_genres) { free(cddb_genres); cddb_genres = NULL; } while(1) { if(read_from_sock(&inp_buf, cddb_fd, TRUE) != 0) { print_stat_win(_("receiving failed")); close(cddb_fd); destroy_stat_win(); return 1; } if(*inp_buf == '.') { free(inp_buf); break; } pat = strchr(inp_buf, '\n'); if(pat) *pat = 0; pat = strchr(inp_buf, '\r'); if(pat) *pat = 0; if(*inp_buf) { print_stat_win(inp_buf); if(! cddb_genres) { cddb_genres = inp_buf; inp_buf = NULL; } else { cddb_genres = (char *) realloc(cddb_genres, sizeof(char) * (strlen(cddb_genres) + strlen(inp_buf) + 2)); if(! cddb_genres) { wuuush(1); } strcat(cddb_genres, ","); strcat(cddb_genres, inp_buf); } } if(inp_buf) { free(inp_buf); inp_buf = NULL; } } /* say bye to cddb-server... */ print_stat_win(_("closing connection")); if(write_to_sock("quit\r\n", 6, cddb_fd) == 0) { if(read_from_sock(&inp_buf, cddb_fd, TRUE) != 0) { print_stat_win(_("failed")); } else { print_stat_win(_("closed")); free(inp_buf); } } close(cddb_fd); destroy_stat_win(); return 0; } char *cddb_select_cddb_genre(char *addr) { field_select_typ *anchor, *curr, *new; char *pat, *pat2; while(1) { anchor = NULL; curr = NULL; pat = cddb_genres; while(pat) { pat2 = strchr(pat, ','); if(pat2) *pat2 = 0; if(*pat) { new = (field_select_typ *) malloc(sizeof(field_select_typ)); if(! new) { wuuush(1); } new->field = copy_char_str(pat); new->dest = NULL; new->information = NULL; new->next = NULL; new->prev = curr; if(curr) curr->next = new; if(! anchor) anchor = new; curr = new; } if(pat2) { *pat2 = ','; pat2++; } pat = pat2; } new = (field_select_typ *) malloc(sizeof(field_select_typ)); if(! new) { wuuush(1); } new->field = copy_char_str(_("refresh genres (requires CDDB-access)")); new->dest = NULL; new->information = copy_char_str("0"); new->next = NULL; new->prev = curr; if(curr) curr->next = new; if(! anchor) anchor = new; curr = new; new = (field_select_typ *) malloc(sizeof(field_select_typ)); if(! new) { wuuush(1); } new->field = copy_char_str(_("Abort")); new->dest = NULL; new->information = copy_char_str("1"); new->next = NULL; new->prev = curr; if(curr) curr->next = new; if(! anchor) anchor = new; curr = new; /* open select_box */ new = select_field_box(anchor, 60, _("select CDDB genre"), FALSE, FALSE); if(! new || (new->information && *(new->information) == '1')) { free_field_select(&anchor); return NULL; } if(! new->information) { pat = copy_char_str(new->field); free_field_select(&anchor); return pat; } free_field_select(&anchor); anchor = NULL; cddb_get_genre_list(addr); } } /* add an entry to FILE *fd, and make sure that no line is longer than 80 chars char *value must NOT a constant char array, there will be writes to *value, if more than one line is needed */ int cddb_add_keyword(FILE *fd, char *keyword, char *value) { int i,j; char pat; if(! keyword) { return 1; } if(! value) { fprintf(fd, "%s\n", keyword); return 0; } i = 0; j = strlen(keyword); while(j + strlen(value + i) > 80) { pat = *(value + i + (80-j)); *(value + i + (80-j)) = 0; fprintf(fd, "%s%s\n", keyword, value + i); *(value + i + (80-j)) = pat; i += (80-j); } fprintf(fd, "%s%s\n", keyword, value + i); return 0; } int cddb_create_entry(char *filename, song_typ *song_list) { BOOL if_various; song_typ *curr; char *artist, *album; FILE *cddb_out_fd; time_t lt; struct tm *ltm; char *pat, *tmp_str; int i; char keyword[10]; if((!song_list) || (!filename)) { return 1; } if_various = FALSE; curr = song_list; artist = curr->artist; while(curr) { if((! artist) || (! *artist)) { artist = curr->artist; } else if(curr->artist && *(curr->artist)) { if(strcmp(artist, curr->artist) != 0) { if_various = TRUE; break; } } curr = curr->next; } artist = NULL; album = NULL; curr = song_list; while(curr) { if(((! artist) || (! *artist)) && curr->artist) { artist = curr->artist; } if(((! album) || (! *album)) && curr->album) { album = curr->album; } if(artist && *artist && album && *album) break; curr = curr->next; } if(artist && (! *artist)) artist = NULL; if(album && (! *album)) album = NULL; if(! artist) { popup_error_win(_("all artist fields are empty")); return 1; } if(! album) { popup_error_win(_("album title is missing")); return 1; } cddb_out_fd = fopen(filename, "w"); if(! cddb_out_fd) { pat = (char *) malloc(sizeof(char) * (strlen(filename) + 100)); if(! pat) { wuuush(1); } sprintf(pat, _("opening \"%s\" for writing failed."), filename); popup_error_win(pat); free(pat); pat = NULL; return 1; } lt = time(NULL); ltm = localtime(<); tmp_str = copy_char_str(ctime(<)); if(tmp_str) { pat = strchr(tmp_str, '\n'); if(pat) *pat = 0; pat = strchr(tmp_str, '\r'); if(pat) *pat = 0; } else { tmp_str = (char *) malloc(sizeof(char) * 100); if(! tmp_str) { wuuush(1); } sprintf(tmp_str, "%s %s %2d %02d:%02d:%02d %4d", weekday[ltm->tm_wday], month[ltm->tm_mon], ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec, ltm->tm_year + 100); } fprintf(cddb_out_fd, "# xmcd CD database file\n" "# Generated: %s by WSPse's MP3c\n" "#\n" "# Track frame offsets:\n", tmp_str); free(tmp_str); tmp_str = NULL; for(i=0;i")); return 1; } /* discid $00000000 is illegal! */ if(cddb_discid(track_last) == 0L) { popup_error_win(_("illegal discid")); return 1; } snprintf(discid, 9, "%08lx", cddb_discid(track_last)); genre = cddb_select_cddb_genre(def_cddb_server); if(! genre) { return 1; } filename = (char *) malloc(sizeof(char) * (strlen(genre) + strlen(cddb_path) + 11)); if(! filename) { wuuush(1); } sprintf(filename, "%s/%s/%s", cddb_path, genre, discid); free(genre); genre = NULL; filename = kill_double_slashs(filename); create_sub_dirs(filename, TRUE); i = 0; if(access(filename, F_OK) == 0) { /* CDDB entry already exists */ if(access(filename, W_OK) != 0) { /* but could not be overwritten */ popup_error_win(_("CDDB entry exists and could not be overwritten")); i = 1; } else { if(! select_yesno_box(_("overwrite existing CDDB entry?"))) { i = 2; } } } if(! i) { i = cddb_create_entry(filename, song_list); if(! i) { popup_error_win(_("CDDB entry saved")); } } free(filename); filename = NULL; return i; } int cddb_wait_smtp_code(int sock_fd) { char *line; char *line2; int ret_val; usleep(150000); if(read_from_sock(&line, sock_fd, TRUE)) { popup_error_win(_("timeout")); return -1; } line2 = NULL; while(! read_from_sock(&line2, sock_fd, FALSE)) { if(line) free(line); line = line2; line2 = NULL; } if(line2) { if(line) free(line); line = line2; } if(! line) { popup_error_win(_("no data from mailserver")); return -1; } line2 = strchr(line, '\n'); if(line2) *line2 = 0; line2 = strchr(line, '\r'); if(line2) *line2 = 0; if(*line == '2') ret_val = 2; else if(*line == '3') ret_val = 3; else { ret_val = -2; popup_error_win(line); write_to_sock("QUIT\n", 5, sock_fd); } free(line); return ret_val; } /* remote transfer of CDDB entry *filename */ int cddb_remote_transfer_entry(char *filename, char *subject, char *smtp_serv, char *from, char **rcpt, char *rcpt_list) { int smtp_fd; char *buf, *tmp; int i, j; FILE *mail; char buffer[SMTP_MAXLEN]; if((!filename) || (!subject)) { return 1; } if(! smtp_serv) { popup_error_win(_("no SMTP server set")); return 1; } if(! from) { popup_error_win(_("missing eMail address")); return 1; } if((!rcpt) || (!rcpt[0]) || (!rcpt_list)) { popup_error_win(_("missing CDDB recipient")); return 1; } print_stat_win(_("connect to SMTP-server")); smtp_fd = open_socket(smtp_serv); if(smtp_fd == -1) { return 1; } /* connected to SMTP Server */ print_stat_win(_("waiting for greeting")); while(1) { if(read_from_sock(&buf, smtp_fd, TRUE) != 0) { close(smtp_fd); return 1; } if(strncmp(buf, "2", 1) == 0) break; free(buf); } free(buf); tmp = getenv("HOSTNAME"); if(tmp) i = strlen(tmp) + 10; else i = 20; buf = (char *) malloc(sizeof(char) * i); if(! buf) { wuuush(1); } if(tmp) { sprintf(buf, "EHLO %s\n", tmp); } else { strcpy(buf, "EHLO localhost\n"); } print_stat_win(_("saying hello to SMTP-server")); if(write_to_sock(buf, strlen(buf), smtp_fd) != 0) { popup_error_win(_("SMTP EHLO failed")); close(smtp_fd); free(buf); return 1; } free(buf); i = cddb_wait_smtp_code(smtp_fd); if(i != 2) { popup_error_win(_("SMTP defered connection (EHLO)")); close(smtp_fd); return 1; } buf = (char *) malloc(sizeof(char) * (strlen(from) + 20)); if(! buf) { wuuush(1); } sprintf(buf, "MAIL FROM: <%s>\n", from); print_stat_win(_("submitting from address")); if(write_to_sock(buf, strlen(buf), smtp_fd) != 0) { popup_error_win(_("MAIL FROM failed")); close(smtp_fd); free(buf); return 1; } free(buf); i = cddb_wait_smtp_code(smtp_fd); if(i != 2) { popup_error_win(_("SMTP defered connection (MAIL FROM)")); close(smtp_fd); return 1; } print_stat_win(_("submitting recipient address")); j = 0; while(rcpt[j]) { buf = (char *) malloc(sizeof(char) * (strlen(rcpt[j]) + 20)); if(! buf) { wuuush(1); } sprintf(buf, "RCPT TO: <%s>", rcpt[j]); print_stat_win(buf); strcat(buf, "\n"); if(write_to_sock(buf, strlen(buf), smtp_fd) != 0) { popup_error_win(_("RCPT TO failed")); close(smtp_fd); free(buf); return 1; } i = cddb_wait_smtp_code(smtp_fd); if(i != 2) { sprintf(buf, _("relay defered: %s"), rcpt[j]); popup_error_win(buf); close(smtp_fd); free(buf); return 1; } free(buf); buf = NULL; j++; } print_stat_win(_("preparing data transfer")); if(write_to_sock("DATA\n", 5, smtp_fd) != 0) { popup_error_win(_("SMTP: DATA cmd failed")); close(smtp_fd); return 1; } i = cddb_wait_smtp_code(smtp_fd); if(i != 3) { popup_error_win(_("SMTP defered data transfer")); close(smtp_fd); return 1; } buf = (char *) malloc(sizeof(char) * ((strlen(from) * 2) + strlen(subject) + strlen(rcpt_list) + 100)); if(! buf) { wuuush(1); } sprintf(buf, "From: %s\n" "Reply-To: %s\n" "To: %s\n" "Subject: %s\n" "\n\n", from, from, rcpt_list, subject); if(write_to_sock(buf, strlen(buf), smtp_fd) != 0) { popup_error_win(_("SMTP: sending header failed")); close(smtp_fd); free(buf); return 1; } free(buf); mail = fopen(filename, "r"); if(! mail) { popup_error_win(_("failed to open CDDB entry")); close(smtp_fd); return 1; } while(1) { fgets(buffer, SMTP_MAXLEN-1, mail); if(feof(mail)) break; if(strcmp(buffer, ".\n") == 0) { i = write_to_sock(". \n", 3, smtp_fd); } else { i = write_to_sock(buffer, strlen(buffer), smtp_fd); } if(i) { popup_error_win(_("failure while sending data to server")); close(smtp_fd); return 1; } } fclose(mail); if(write_to_sock(".\n", 2, smtp_fd)) { popup_error_win(_("SMTP: mail closing timeout")); close(smtp_fd); return 1; } i = cddb_wait_smtp_code(smtp_fd); if(i != 2) { popup_error_win(_("error delivering mail")); j = 1; } else { write_to_sock("QUIT\n", 5, smtp_fd); j = 0; } close(smtp_fd); return j; } void cddb_add_rcpt(char ***list, char *entry) { int i; if(! *list) { *list = (char **) malloc(sizeof(char *) * 2); if(! *list) { wuuush(1); } (*list)[0] = copy_char_str(entry); (*list)[1] = NULL; } else { i = 0; while((*list)[i]) i++; *list = (char **) realloc(*list, sizeof(char *) * (i+2)); if(! *list) { wuuush(1); } (*list)[i] = copy_char_str(entry); (*list)[i+1] = NULL; } } /* submit CDDB entry */ int cddb_submit_cddb_entry(song_typ *song_list) { char *genre; char discid[9]; char *filename; char *subject; int i; char *serv, *match; BOOL replaced; char **rcpt; if(! song_list) { popup_error_win(_("no CD inserted")); return 1; } if(!config_cddb_enbl) { popup_error_win(_("CDDB access is locked, use \"l\" to unlock")); return 1; } /* discid $00000000 is illegal! */ if(cddb_discid(track_last) == 0L) { popup_error_win(_("illegal discid")); return 1; } snprintf(discid, 9, "%08lx", cddb_discid(track_last)); if(def_tmp_file) { filename = (char *) malloc(sizeof(char) * (strlen(def_tmp_file) + 25)); if(! filename) { wuuush(1); } sprintf(filename, "%s_tmp_%s_%d", def_tmp_file, discid, getpid()); } else { filename = copy_char_str("/tmp/mp3c_tmp_cddb_entry"); } if(cddb_create_entry(filename, song_list)) { popup_error_win(_("could not create tmpfile with CDDB entry")); unlink(filename); free(filename); return 1; } genre = cddb_select_cddb_genre(def_cddb_server); if(! genre) { unlink(filename); free(filename); return 1; } subject = (char *) malloc(sizeof(char) * (strlen(genre) + 15)); if(! subject) { wuuush(1); } sprintf(subject, "cddb %s %s", genre, discid); free(genre); genre = NULL; serv = def_cddb_email; rcpt = NULL; while(1) { replaced = FALSE; match = strchr(serv, ','); if(match) { *match = 0; replaced = TRUE; } cddb_add_rcpt(&rcpt, serv); if(replaced) { *match = ','; serv = match+1; } if((!replaced) || (!(*serv))) break; } setup_stat_win(70); i = cddb_remote_transfer_entry(filename, subject, def_smtp_server, def_my_email, rcpt, def_cddb_email); free_char_array(rcpt); destroy_stat_win(); free(subject); subject = NULL; unlink(filename); free(filename); filename = NULL; if(i) { popup_error_win(_("transmission failed")); } else { popup_error_win(_("CDDB entry transmitted successfully")); cddb_cddb_entry_is_clean = TRUE; } return i; }