Beispiel #1
0
/* Return the number of files matching the query, or -1 for an error */
static int
count_files (notmuch_query_t *query)
{
    notmuch_messages_t *messages;
    notmuch_message_t *message;
    notmuch_filenames_t *filenames;
    notmuch_status_t status;
    int count = 0;

    status = notmuch_query_search_messages_st (query, &messages);
    if (print_status_query ("notmuch count", query, status))
        return -1;

    for (;
            notmuch_messages_valid (messages);
            notmuch_messages_move_to_next (messages)) {
        message = notmuch_messages_get (messages);
        filenames = notmuch_message_get_filenames (message);

        for (;
                notmuch_filenames_valid (filenames);
                notmuch_filenames_move_to_next (filenames))
            count++;

        notmuch_filenames_destroy (filenames);
        notmuch_message_destroy (message);
    }

    notmuch_messages_destroy (messages);

    return count;
}
Beispiel #2
0
static int remove_filename(struct nm_ctxdata *data, const char *path)
{
    notmuch_status_t st;
    notmuch_filenames_t *ls;
    notmuch_message_t *msg = NULL;
    notmuch_database_t *db = get_db(data, TRUE);
    int trans;

    dprint(2, (debugfile, "nm: remove filename '%s'\n", path));

    if (!db)
        return -1;
    st = notmuch_database_find_message_by_filename(db, path, &msg);
    if (st || !msg)
        return -1;
    trans = db_trans_begin(data);
    if (trans < 0)
        return -1;

    /*
     * note that unlink() is probably unnecessary here, it's already removed
     * by mh_sync_mailbox_message(), but for sure...
     */
    st = notmuch_database_remove_message(db, path);
    switch (st) {
    case NOTMUCH_STATUS_SUCCESS:
        dprint(2, (debugfile, "nm: remove success, call unlink\n"));
        unlink(path);
        break;
    case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
        dprint(2, (debugfile, "nm: remove succes (duplicate), call unlink\n"));
        unlink(path);
        for (ls = notmuch_message_get_filenames(msg);
                ls && notmuch_filenames_valid(ls);
                notmuch_filenames_move_to_next(ls)) {

            path = notmuch_filenames_get(ls);

            dprint(2, (debugfile, "nm: remove duplicate: '%s'\n", path));
            unlink(path);
            notmuch_database_remove_message(db, path);
        }
        break;
    default:
        dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n", path, (int) st));
        break;
    }

    notmuch_message_destroy(msg);
    if (trans)
        db_trans_end(data);
    return 0;
}
Beispiel #3
0
static const char *get_message_last_filename(notmuch_message_t *msg)
{
    notmuch_filenames_t *ls;
    const char *name = NULL;

    for (ls = notmuch_message_get_filenames(msg);
            ls && notmuch_filenames_valid(ls);
            notmuch_filenames_move_to_next(ls)) {

        name = notmuch_filenames_get(ls);
    }

    return name;
}
Beispiel #4
0
static int
_count_filenames (notmuch_message_t *message)
{
    notmuch_filenames_t *filenames;
    int i = 0;

    filenames = notmuch_message_get_filenames (message);

    while (notmuch_filenames_valid (filenames)) {
        notmuch_filenames_move_to_next (filenames);
        i++;
    }

    notmuch_filenames_destroy (filenames);

    return i;
}
Beispiel #5
0
static int
msg_filenames(Tcl_Interp *interp, notmuch_message_t *msg, int argc, const char *argv[]) {
    if (argc != 0) {
        tcl_result_printf(interp, "msg filenames takes no arguments");
        return TCL_ERROR;
    }

    Tcl_Obj* list = Tcl_NewListObj(0, NULL);
    if (!list) {
        return TCL_ERROR;
    }
    notmuch_filenames_t *fns = notmuch_message_get_filenames(msg);
    while (notmuch_filenames_valid(fns)) {
        const char *fn = notmuch_filenames_get(fns);
        Tcl_ListObjAppendElement(interp, list, Tcl_NewStringObj(fn, -1));
        notmuch_filenames_move_to_next(fns);
    }
    notmuch_filenames_destroy(fns);

    Tcl_SetObjResult(interp, list);
    return TCL_OK;
}
Beispiel #6
0
int
cmd_move_message(ClientData data, Tcl_Interp *interp, int argc, const char *argv[]) {
    filter_context_t *ctx = FILTER_CONTEXT(data);
    notmuch_message_t *msg = ctx->current_message;
    notmuch_status_t nmrc;

    if (argc != 2) {
        tcl_result_printf(interp, "wrong # of args: got %d, expected move folder", argc);
        return TCL_ERROR;
    }
    
    const char *folder = argv[1];
    if (folder[0] == '/') {
        tcl_result_printf(interp, "invalid folder '%s'", folder);
        return TCL_ERROR;
    }

    log_debug("moving message %s to folder %s",
              notmuch_message_get_message_id(msg), folder);
    char *folder_path = g_strdup_printf("%s/%s",
                                        notmuch_database_get_path(ctx->database),
                                        folder);
    int status = TCL_ERROR;

    notmuch_filenames_t *fns = notmuch_message_get_filenames(msg);
    int nmoved = 0;
    while (notmuch_filenames_valid(fns)) {
        const char *fn = notmuch_filenames_get(fns);
        char *new_fn = NULL;
        if (g_str_has_prefix(fn, folder_path)) {
            log_debug("file %s already in folder %s", fn, folder);
        } else if (ctx->dry_run) {
            log_debug("moving %s to folder %s", fn, folder);
        } else {
            log_debug("moving %s to folder %s", fn, folder);
            int rc = maildir_deliver_link(fn, folder_path, &new_fn);
            if (rc) {
                tcl_result_printf(interp, "delivery error: %s", strerror(errno));
                goto done;
            }
            log_debug("delivered as %s", new_fn);
            nmrc = notmuch_database_add_message(ctx->database, new_fn, NULL);
            switch (nmrc) {
                case NOTMUCH_STATUS_SUCCESS:
                    log_warning("%s: message was not in database", new_fn);
                case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
                    log_debug("added new file to database");
                    break;
                default:
                    tcl_result_printf(interp, "error adding %s to database: %s",
                                      new_fn,
                                      notmuch_status_to_string(nmrc));
                    goto done;
            }
            nmrc = notmuch_database_remove_message(ctx->database, fn);
            switch (nmrc) {
                case NOTMUCH_STATUS_SUCCESS:
                    log_warning("%s: file was only file for message", fn);
                case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
                    log_debug("removed file %s from database", fn);
                    break;
                default:
                    tcl_result_printf(interp, "error removing %s from database: %s",
                                      fn, notmuch_status_to_string(nmrc));
                    goto done;
            }
            if (unlink(fn)) {
                tcl_result_printf(interp, "error unlinking %s: %s", fn, strerror(errno));
                goto done;
            }
            nmoved += 1;
        }
        notmuch_filenames_move_to_next(fns);
    }
    notmuch_filenames_destroy(fns);
    fns = NULL;

    if (nmoved == 0) {
        Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
        status = TCL_OK;
        goto done;
    }

    log_debug("syncing maildir flags");
    
    const char *mid = notmuch_message_get_message_id(msg);
    nmrc = notmuch_database_find_message(ctx->database, mid, &msg);
    if (nmrc != NOTMUCH_STATUS_SUCCESS) {
        tcl_result_printf(interp, "cannot re-find message %s", mid);
        goto done;
    }
    notmuch_message_destroy(ctx->current_message);
    ctx->current_message = msg;
    nmrc = notmuch_message_tags_to_maildir_flags(msg);
    if (nmrc != NOTMUCH_STATUS_SUCCESS) {
        tcl_result_printf(interp, "error syncing tags back to flags");
        goto done;
    }

    Tcl_SetObjResult(interp, Tcl_NewIntObj(nmoved));
    status = TCL_OK;

done:
    if (fns) {
        notmuch_filenames_destroy(fns);
    }
    g_free(folder_path);
    return status;
}
Beispiel #7
0
static int
do_search_messages (search_context_t *ctx)
{
    notmuch_message_t *message;
    notmuch_messages_t *messages;
    notmuch_filenames_t *filenames;
    sprinter_t *format = ctx->format;
    int i;
    notmuch_status_t status;

    if (ctx->offset < 0) {
	unsigned count;
	notmuch_status_t status;
	status = notmuch_query_count_messages_st (ctx->query, &count);
	if (print_status_query ("notmuch search", ctx->query, status))
	    return 1;

	ctx->offset += count;
	if (ctx->offset < 0)
	    ctx->offset = 0;
    }

    status = notmuch_query_search_messages_st (ctx->query, &messages);
    if (print_status_query ("notmuch search", ctx->query, status))
	return 1;

    format->begin_list (format);

    for (i = 0;
	 notmuch_messages_valid (messages) && (ctx->limit < 0 || i < ctx->offset + ctx->limit);
	 notmuch_messages_move_to_next (messages), i++)
    {
	if (i < ctx->offset)
	    continue;

	message = notmuch_messages_get (messages);

	if (ctx->output == OUTPUT_FILES) {
	    int j;
	    filenames = notmuch_message_get_filenames (message);

	    for (j = 1;
		 notmuch_filenames_valid (filenames);
		 notmuch_filenames_move_to_next (filenames), j++)
	    {
		if (ctx->dupe < 0 || ctx->dupe == j) {
		    format->string (format, notmuch_filenames_get (filenames));
		    format->separator (format);
		}
	    }
	    
	    notmuch_filenames_destroy( filenames );

	} else if (ctx->output == OUTPUT_MESSAGES) {
            /* special case 1 for speed */
            if (ctx->dupe <= 1 || ctx->dupe <= _count_filenames (message)) {
                format->set_prefix (format, "id");
                format->string (format,
                                notmuch_message_get_message_id (message));
                format->separator (format);
            }
	} else {
	    if (ctx->output & OUTPUT_SENDER) {
		const char *addrs;

		addrs = notmuch_message_get_header (message, "from");
		process_address_header (ctx, addrs);
	    }

	    if (ctx->output & OUTPUT_RECIPIENTS) {
		const char *hdrs[] = { "to", "cc", "bcc" };
		const char *addrs;
		size_t j;

		for (j = 0; j < ARRAY_SIZE (hdrs); j++) {
		    addrs = notmuch_message_get_header (message, hdrs[j]);
		    process_address_header (ctx, addrs);
		}
	    }
	}

	notmuch_message_destroy (message);
    }

    if (ctx->addresses &&
	(ctx->output & OUTPUT_COUNT || ctx->dedup == DEDUP_ADDRESS))
	g_hash_table_foreach (ctx->addresses, print_hash_value, ctx);

    notmuch_messages_destroy (messages);

    format->end (format);

    return 0;
}
Beispiel #8
0
static int
do_search_messages (const search_format_t *format,
		    notmuch_query_t *query,
		    output_t output,
		    int offset,
		    int limit)
{
    notmuch_message_t *message;
    notmuch_messages_t *messages;
    notmuch_filenames_t *filenames;
    int first_message = 1;
    int i;

    if (offset < 0) {
	offset += notmuch_query_count_messages (query);
	if (offset < 0)
	    offset = 0;
    }

    messages = notmuch_query_search_messages (query);
    if (messages == NULL)
	return 1;

    fputs (format->results_start, stdout);

    for (i = 0;
	 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
	 notmuch_messages_move_to_next (messages), i++)
    {
	if (i < offset)
	    continue;

	message = notmuch_messages_get (messages);

	if (output == OUTPUT_FILES) {
	    filenames = notmuch_message_get_filenames (message);

	    for (;
		 notmuch_filenames_valid (filenames);
		 notmuch_filenames_move_to_next (filenames))
	    {
		if (! first_message)
		    fputs (format->item_sep, stdout);

		format->item_id (message, "",
				 notmuch_filenames_get (filenames));

		first_message = 0;
	    }
	    
	    notmuch_filenames_destroy( filenames );

	} else { /* output == OUTPUT_MESSAGES */
	    if (! first_message)
		fputs (format->item_sep, stdout);

	    format->item_id (message, "id:",
			     notmuch_message_get_message_id (message));
	    first_message = 0;
	}

	notmuch_message_destroy (message);
    }

    notmuch_messages_destroy (messages);

    if (first_message)
	fputs (format->results_null, stdout);
    else
	fputs (format->results_end, stdout);

    return 0;
}