X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=aft.c;h=8c7dd21a0f86ac25e39b1bfdae33ccc5f6032b71;hp=9e4fec288d63e84c8c05139f727516a1a5ca4f43;hb=e60387b0557fbeb97895bc3d6d4423be12436c52;hpb=b58faecc81c50be4723e973dcf9a65140d30e037 diff --git a/aft.c b/aft.c index 9e4fec28..8c7dd21a 100644 --- a/aft.c +++ b/aft.c @@ -457,9 +457,9 @@ static int load_chunk_info(struct osl_object *obj, struct audio_format_info *afh * * \return The return value of the underlying call to osl_get_row(). */ -int aft_get_row_of_path(char *path, struct osl_row **row) +int aft_get_row_of_path(const char *path, struct osl_row **row) { - struct osl_object obj = {.data = path, .size = strlen(path) + 1}; + struct osl_object obj = {.data = (char *)path, .size = strlen(path) + 1}; return osl_get_row(audio_file_table, AFTCOL_PATH, &obj, row); } @@ -500,7 +500,7 @@ int get_afsi_object_of_row(const struct osl_row *row, struct osl_object *obj) * * \return Positive on success, negative on errors. */ -int get_afsi_object_of_path(char *path, struct osl_object *obj) +int get_afsi_object_of_path(const char *path, struct osl_object *obj) { struct osl_row *row; int ret = aft_get_row_of_path(path, &row); @@ -526,6 +526,23 @@ int get_afsi_of_row(const struct osl_row *row, struct afs_info *afsi) return load_afsi(afsi, &obj); } +/** + * Get the audio file selector info, given the path of an audio table. + * + * \param path The full path of the audio file. + * \param afsi Result pointer. + * + * \return Positive on success, negative on errors. + */ +int get_afsi_of_path(const char *path, struct afs_info *afsi) +{ + struct osl_object obj; + int ret = get_afsi_object_of_path(path, &obj); + if (ret < 0) + return ret; + return load_afsi(afsi, &obj); +} + /** * Get the path of an audio file, given a row of the audio file table. * @@ -683,12 +700,17 @@ err: } static int get_local_time(uint64_t *seconds, char *buf, size_t size, - time_t current_time) + time_t current_time, enum ls_listing_mode lm) { struct tm t; if (!localtime_r((time_t *)seconds, &t)) return -E_LOCALTIME; + if (lm == LS_MODE_MBOX) { + if (!strftime(buf, size, "%c", &t)) + return -E_STRFTIME; + return 1; + } if (*seconds + 6 * 30 * 24 * 3600 > current_time) { if (!strftime(buf, size, "%b %e %k:%M", &t)) return -E_STRFTIME; @@ -775,6 +797,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, struct audio_format_info *afhi = &d->afhi; struct ls_widths *w = &opts->widths; int have_score = opts->flags & LS_FLAG_ADMISSIBLE_ONLY; + char asc_hash[2 * HASH_SIZE + 1]; + char *att_line, *lyrics_line, *image_line; if (opts->mode == LS_MODE_SHORT) { para_printf(b, "%s\n", d->path); @@ -782,7 +806,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, } get_attribute_bitmap(&afsi->attributes, att_buf); ret = get_local_time(&afsi->last_played, last_played_time, - sizeof(last_played_time), current_time); + sizeof(last_played_time), current_time, opts->mode); if (ret < 0) return ret; get_duration_buf(afhi->seconds_total, duration_buf, w->duration_width); @@ -823,14 +847,12 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, ); return 1; } + hash_to_asc(d->hash, asc_hash); + att_line = make_attribute_line(att_buf, afsi); + lyrics_line = make_lyrics_line(afsi); + image_line = make_image_line(afsi); if (opts->mode == LS_MODE_VERBOSE) { - char asc_hash[2 * HASH_SIZE + 1]; - char *att_line, *lyrics_line, *image_line; - hash_to_asc(d->hash, asc_hash); - att_line = make_attribute_line(att_buf, afsi); - lyrics_line = make_lyrics_line(afsi); - image_line = make_image_line(afsi); para_printf(b, "%s: %s\n" /* path */ "%s%s%s" /* score */ @@ -863,11 +885,50 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, last_played_time, afhi->info_string ); - free(att_line); - free(lyrics_line); - free(image_line); - return 1; + } else { /* mbox mode */ + struct osl_object lyrics_def; + lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def); + para_printf(b, + "From foo@localhost %s\n" + "Received: from\nTo: bar\nFrom: a\n" + "Subject: %s\n\n" /* path */ + "%s%s%s" /* score */ + "attributes: %s\n" + "hash: %s\n" + "image_id: %s\n" + "lyrics_id: %s\n" + "bitrate: %dkbit/s\n" + "format: %s\n" + "frequency: %dHz\n" + "channels: %d\n" + "duration: %s\n" + "num_played: %d\n" + "tag info: %s\n" + "%s%s\n", + last_played_time, + d->path, + have_score? "score: " : "", score_buf, + have_score? "\n" : "", + att_line, + asc_hash, + image_line, + lyrics_line, + afhi->bitrate, + audio_format_name(afsi->audio_format_id), + afhi->frequency, + afhi->channels, + duration_buf, + afsi->num_played, + afhi->info_string, + lyrics_def.data? "Lyrics:\n~~~~~~~\n" : "", + lyrics_def.data? (char *)lyrics_def.data : "" + ); + if (lyrics_def.data) + osl_close_disk_object(lyrics_def.data); } + free(att_line); + free(lyrics_line); + free(image_line); return 1; } @@ -1357,6 +1418,7 @@ afhi <=> force or no HS #define ADD_FLAG_LAZY 1 #define ADD_FLAG_FORCE 2 #define ADD_FLAG_VERBOSE 4 +#define ADD_FLAG_ALL 8 /* TODO: change log messages so that they get written to the result buffer */ @@ -1520,6 +1582,14 @@ static int add_one_audio_file(const char *arg, const void *private_data) ret = verify_path(arg, &path); if (ret < 0) goto out_free; + ret = guess_audio_format(path); + if (ret < 0 && !(pad->flags & ADD_FLAG_ALL)) { + if (pad->flags & ADD_FLAG_VERBOSE) + ret = send_va_buffer(pad->fd, "%s: %s\n", + PARA_STRERROR(-ret), path); + ret = 1; + goto out_free; + } query.data = path; query.size = strlen(path) + 1; ret = send_callback_request(path_brother_callback, &query, &result); @@ -1570,8 +1640,11 @@ static int add_one_audio_file(const char *arg, const void *private_data) format_num = ret; afhi_ptr = &afhi; } - if (pad->flags & ADD_FLAG_VERBOSE) - send_va_buffer(pad->fd, "adding %s\n", path); + if (pad->flags & ADD_FLAG_VERBOSE) { + ret = send_va_buffer(pad->fd, "adding %s\n", path); + if (ret < 0) + goto out_unmap; + } munmap(map.data, map.size); save_audio_file_info(hash, path, afhi_ptr, pad->flags, format_num, &obj); /* Ask afs to consider this entry for adding. */ @@ -1581,14 +1654,15 @@ static int add_one_audio_file(const char *arg, const void *private_data) out_unmap: munmap(map.data, map.size); out_free: - if (ret < 0) + if (ret < 0 && ret != -E_SEND) send_va_buffer(pad->fd, "failed to add %s (%s)\n", path? path : arg, PARA_STRERROR(-ret)); free(obj.data); free(path); if (afhi_ptr) free(afhi_ptr->chunk_table); - return 1; /* it's not an error if not all files could be added */ + /* it's not an error if not all files could be added */ + return ret == -E_SEND? ret : 1; } int com_add(int fd, int argc, char * const * const argv) @@ -1605,6 +1679,10 @@ int com_add(int fd, int argc, char * const * const argv) i++; break; } + if (!strcmp(arg, "-a")) { + pad.flags |= ADD_FLAG_ALL; + continue; + } if (!strcmp(arg, "-l")) { pad.flags |= ADD_FLAG_LAZY; continue; @@ -1629,12 +1707,18 @@ int com_add(int fd, int argc, char * const * const argv) if (ret < 0) PARA_NOTICE_LOG("failed to stat %s (%s)", path, strerror(errno)); - else + else { if (S_ISDIR(statbuf.st_mode)) - for_each_file_in_dir(path, add_one_audio_file, + ret = for_each_file_in_dir(path, add_one_audio_file, &pad); else - add_one_audio_file(path, &pad); + ret = add_one_audio_file(path, &pad); + if (ret < 0) { + send_va_buffer(fd, "%s: %s\n", path, PARA_STRERROR(-ret)); + free(path); + return ret; + } + } free(path); } ret = 1; @@ -1733,7 +1817,6 @@ static int com_touch_callback(const struct osl_object *query, return ret < 0? ret : 0; } - int com_touch(int fd, int argc, char * const * const argv) { struct com_touch_options cto = { @@ -1907,6 +1990,146 @@ int com_afs_rm(int fd, int argc, char * const * const argv) return ret; } +enum cpsi_flags { + CPSI_FLAG_COPY_LYRICS_ID = 1, + CPSI_FLAG_COPY_IMAGE_ID = 2, + CPSI_FLAG_COPY_LASTPLAYED = 4, + CPSI_FLAG_COPY_NUMPLAYED = 8, + CPSI_FLAG_COPY_ATTRIBUTES = 16, + CPSI_FLAG_VERBOSE = 32, +}; + +struct cpsi_action_data { + unsigned flags; + unsigned num_copied; + struct para_buffer pb; + struct afs_info source_afsi; +}; + +static int copy_selector_info(__a_unused struct osl_table *table, + struct osl_row *row, const char *name, void *data) +{ + struct cpsi_action_data *cad = data; + struct osl_object target_afsi_obj; + int ret; + struct afs_info target_afsi; + + ret = get_afsi_object_of_row(row, &target_afsi_obj); + if (ret < 0) + return ret; + load_afsi(&target_afsi, &target_afsi_obj); + if (cad->flags & CPSI_FLAG_COPY_LYRICS_ID) + target_afsi.lyrics_id = cad->source_afsi.lyrics_id; + if (cad->flags & CPSI_FLAG_COPY_IMAGE_ID) + target_afsi.image_id = cad->source_afsi.image_id; + if (cad->flags & CPSI_FLAG_COPY_LASTPLAYED) + target_afsi.last_played = cad->source_afsi.last_played; + if (cad->flags & CPSI_FLAG_COPY_NUMPLAYED) + target_afsi.num_played = cad->source_afsi.num_played; + if (cad->flags & CPSI_FLAG_COPY_ATTRIBUTES) + target_afsi.attributes = cad->source_afsi.attributes; + save_afsi(&target_afsi, &target_afsi_obj); /* in-place update */ + cad->num_copied++; + if (cad->flags & CPSI_FLAG_VERBOSE) + para_printf(&cad->pb, "copied afsi to %s\n", name); + return 1; +} + +static int com_cpsi_callback(const struct osl_object *query, + struct osl_object *result) +{ + struct cpsi_action_data cad = {.flags = *(unsigned *)query->data}; + int ret; + char *source_path = (char *)query->data + sizeof(cad.flags); + + ret = get_afsi_of_path(source_path, &cad.source_afsi); + if (ret < 0) + goto out; + struct pattern_match_data pmd = { + .table = audio_file_table, + .loop_col_num = AFTCOL_HASH, + .match_col_num = AFTCOL_PATH, + .patterns = {.data = source_path + strlen(source_path) + 1, + .size = query->size - sizeof(cad.flags) + - strlen(source_path) - 1}, + .data = &cad, + .action = copy_selector_info + }; + ret = for_each_matching_row(&pmd); +out: + if (ret < 0) + para_printf(&cad.pb, "%s\n", PARA_STRERROR(-ret)); + if (cad.flags & CPSI_FLAG_VERBOSE) { + if (cad.num_copied) + para_printf(&cad.pb, "copied requested afsi from %s " + "to %u files\n", + source_path, cad.num_copied); + else + para_printf(&cad.pb, "nothing copied\n"); + } + if (cad.pb.buf) { + result->data = cad.pb.buf; + result->size = cad.pb.size; + return 1; + } + return ret < 0? ret : 0; +} + +int com_cpsi(int fd, int argc, char * const * const argv) +{ + unsigned flags = 0; + int i, ret; + struct osl_object options = {.data = &flags, .size = sizeof(flags)}, + result; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (arg[0] != '-') + break; + if (!strcmp(arg, "--")) { + i++; + break; + } + if (!strcmp(arg, "-y")) { + flags |= CPSI_FLAG_COPY_LYRICS_ID; + continue; + } + if (!strcmp(arg, "-i")) { + flags |= CPSI_FLAG_COPY_IMAGE_ID; + continue; + } + if (!strcmp(arg, "-l")) { + flags |= CPSI_FLAG_COPY_LASTPLAYED; + continue; + } + if (!strcmp(arg, "-n")) { + flags |= CPSI_FLAG_COPY_NUMPLAYED; + continue; + } + if (!strcmp(arg, "-a")) { + flags |= CPSI_FLAG_COPY_ATTRIBUTES; + continue; + } + if (!strcmp(arg, "-v")) { + flags |= CPSI_FLAG_VERBOSE; + continue; + } + break; + } + if (i + 1 >= argc) /* need at least souce file and pattern */ + return -E_AFT_SYNTAX; + if (!(flags & ~CPSI_FLAG_VERBOSE)) /* no copy flags given */ + flags = ~(unsigned)CPSI_FLAG_VERBOSE | flags; + ret = send_option_arg_callback_request(&options, argc - i, argv + i, + com_cpsi_callback, &result); + if (ret > 0) { + send_buffer(fd, (char *)result.data); + free(result.data); + } else + send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret)); + return ret; +} + /* TODO: optionally fix problems by removing offending rows */ static int check_audio_file(struct osl_row *row, void *data) { @@ -1955,6 +2178,8 @@ int aft_check_callback(__a_unused const struct osl_object *query, struct osl_obj } + + /** * Close the audio file table. *