/* parse the find parameters, and return the values as out params */ static MuError get_find_params (GSList *args, gboolean *threads, MuMsgFieldId *sortfield, gboolean *reverse, int *maxnum, GError **err) { const char *maxnumstr, *sortfieldstr; /* maximum number of results */ maxnumstr = get_string_from_args (args, "maxnum", TRUE, NULL); *maxnum = maxnumstr ? atoi (maxnumstr) : 0; /* whether to show threads or not */ *threads = get_bool_from_args (args, "threads", TRUE, NULL); *reverse = get_bool_from_args (args, "reverse", TRUE, NULL); /* field to sort by */ sortfieldstr = get_string_from_args (args, "sortfield", TRUE, NULL); if (sortfieldstr) { *sortfield = mu_msg_field_id_from_name (sortfieldstr, FALSE); /* note: shortcuts are not allowed here */ if (*sortfield == MU_MSG_FIELD_ID_NONE) { mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, "not a valid sort field: '%s'", sortfield); return MU_G_ERROR_CODE(err); } } else *sortfield = MU_MSG_FIELD_ID_DATE; return MU_OK; }
MuError mu_cmd_server (MuStore *store, MuConfig *opts/*unused*/, GError **err) { ServerContext ctx; gboolean do_quit; g_return_val_if_fail (store, MU_ERROR_INTERNAL); ctx.store = store; ctx.query = mu_query_new (store, err); if (!ctx.query) return MU_G_ERROR_CODE (err); srand (time(NULL)*getpid()); install_sig_handler (); g_print (";; welcome to " PACKAGE_STRING "\n"); /* the main REPL */ do_quit = FALSE; while (!MU_TERMINATE && !do_quit) { GHashTable *args; GError *my_err; /* args will receive a the command as a list of * strings. returning NULL indicates an error */ my_err = NULL; args = read_command_line (&my_err); if (!args) { if (feof(stdin)) break; if (my_err) print_and_clear_g_error (&my_err); continue; } switch (handle_args (&ctx, args, &my_err)) { case MU_OK: break; case MU_STOP: do_quit = TRUE; break; default: /* some error occurred */ print_and_clear_g_error (&my_err); } g_hash_table_destroy (args); } mu_store_flush (ctx.store); mu_query_destroy (ctx.query); return MU_OK; }
MuError mu_cmd_find (MuStore *store, MuConfig *opts, GError **err) { g_return_val_if_fail (opts, MU_ERROR_INTERNAL); g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_FIND, MU_ERROR_INTERNAL); if (opts->exec) opts->format = MU_CONFIG_FORMAT_EXEC; /* pseudo format */ if (!query_params_valid (opts, err) || !format_params_valid(opts, err)) return MU_G_ERROR_CODE (err); if (!execute_find (store, opts, err)) return MU_G_ERROR_CODE(err); else return MU_OK; }
/* parse the find parameters, and return the values as out params */ static MuError get_find_params (GSList *args, MuMsgFieldId *sortfield, int *maxnum, MuQueryFlags *qflags, GError **err) { const char *maxnumstr, *sortfieldstr; /* defaults */ *maxnum = 500; *qflags = MU_QUERY_FLAG_NONE; *sortfield = MU_MSG_FIELD_ID_NONE; /* field to sort by */ sortfieldstr = get_string_from_args (args, "sortfield", TRUE, NULL); if (sortfieldstr) { *sortfield = mu_msg_field_id_from_name (sortfieldstr, FALSE); /* note: shortcuts are not allowed here */ if (*sortfield == MU_MSG_FIELD_ID_NONE) { mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, "not a valid sort field: '%s'", sortfield); return MU_G_ERROR_CODE(err); } } else *sortfield = MU_MSG_FIELD_ID_DATE; /* maximum number of results */ maxnumstr = get_string_from_args (args, "maxnum", TRUE, NULL); *maxnum = maxnumstr ? atoi (maxnumstr) : 0; if (get_bool_from_args (args, "reverse", TRUE, NULL)) *qflags |= MU_QUERY_FLAG_DESCENDING; if (get_bool_from_args (args, "skip-dups", TRUE, NULL)) *qflags |= MU_QUERY_FLAG_SKIP_DUPS; if (get_bool_from_args (args, "include-related", TRUE, NULL)) *qflags |= MU_QUERY_FLAG_INCLUDE_RELATED; if (get_bool_from_args (args, "include-related", TRUE, NULL)) *qflags |= MU_QUERY_FLAG_INCLUDE_RELATED; if (get_bool_from_args (args, "threads", TRUE, NULL)) *qflags |= MU_QUERY_FLAG_THREADS; return MU_OK; }
static MuError handle_args (ServerContext *ctx, GSList *args, GError **err) { unsigned u; const char *cmd; struct { const char *cmd; CmdFunc func; } cmd_map[] = { { "add", cmd_add }, { "compose", cmd_compose }, { "contacts", cmd_contacts }, { "extract", cmd_extract }, { "find", cmd_find }, { "guile", cmd_guile }, { "index", cmd_index }, { "mkdir", cmd_mkdir }, { "move", cmd_move }, { "ping", cmd_ping }, { "quit", cmd_quit }, { "remove", cmd_remove }, { "sent", cmd_sent }, { "view", cmd_view } }; cmd = (const char*) args->data; /* ignore empty */ if (mu_str_is_empty (cmd)) return MU_OK; for (u = 0; u != G_N_ELEMENTS (cmd_map); ++u) if (g_strcmp0(cmd, cmd_map[u].cmd) == 0) return cmd_map[u].func (ctx, g_slist_next(args), err); mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, "unknown command '%s'", cmd ? cmd : ""); return MU_G_ERROR_CODE (err); }
MuError mu_cmd_execute (MuConfig *opts, GError **err) { g_return_val_if_fail (opts, MU_ERROR_INTERNAL); if (opts->version) { show_version (); return MU_OK; } if (!check_params(opts, err)) return MU_G_ERROR_CODE(err); switch (opts->cmd) { /* already handled in mu-config.c */ case MU_CONFIG_CMD_HELP: return MU_OK; case MU_CONFIG_CMD_CFIND: return mu_cmd_cfind (opts, err); case MU_CONFIG_CMD_MKDIR: return mu_cmd_mkdir (opts, err); case MU_CONFIG_CMD_VIEW: return mu_cmd_view (opts, err); case MU_CONFIG_CMD_VERIFY: return mu_cmd_verify (opts, err); case MU_CONFIG_CMD_EXTRACT: return mu_cmd_extract (opts, err); case MU_CONFIG_CMD_FIND: return with_store (mu_cmd_find, opts, TRUE, err); case MU_CONFIG_CMD_INDEX: return with_store (mu_cmd_index, opts, FALSE, err); case MU_CONFIG_CMD_ADD: return with_store (mu_cmd_add, opts, FALSE, err); case MU_CONFIG_CMD_REMOVE: return with_store (mu_cmd_remove, opts, FALSE, err); case MU_CONFIG_CMD_SERVER: return with_store (mu_cmd_server, opts, FALSE, err); default: show_usage (); g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS, "unknown command '%s'", opts->cmdstr); return MU_ERROR_IN_PARAMETERS; } }
MuError mu_cmd_execute (MuConfig *opts, GError **err) { MuError merr; g_return_val_if_fail (opts, MU_ERROR_INTERNAL); if (!check_params(opts, err)) return MU_G_ERROR_CODE(err); set_log_options (opts); switch (opts->cmd) { /* already handled in mu-config.c */ case MU_CONFIG_CMD_HELP: return MU_OK; case MU_CONFIG_CMD_CFIND: merr = mu_cmd_cfind (opts, err); break; case MU_CONFIG_CMD_MKDIR: merr = mu_cmd_mkdir (opts, err); break; case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script (opts, err); break; case MU_CONFIG_CMD_VIEW: merr = mu_cmd_view (opts, err); break; case MU_CONFIG_CMD_VERIFY: merr = mu_cmd_verify (opts, err); break; case MU_CONFIG_CMD_EXTRACT: merr = mu_cmd_extract (opts, err); break; case MU_CONFIG_CMD_FIND: merr = with_store (mu_cmd_find, opts, TRUE, err); break; case MU_CONFIG_CMD_INDEX: merr = with_store (mu_cmd_index, opts, FALSE, err); break; case MU_CONFIG_CMD_ADD: merr = with_store (mu_cmd_add, opts, FALSE, err); break; case MU_CONFIG_CMD_REMOVE: merr = with_store (mu_cmd_remove, opts, FALSE, err); break; case MU_CONFIG_CMD_SERVER: merr = with_store (mu_cmd_server, opts, FALSE, err); break; default: merr = MU_ERROR_IN_PARAMETERS; break; } return merr; }
static MuError do_move (MuStore *store, unsigned docid, MuMsg *msg, const char *maildir, MuFlags flags, GError **err) { unsigned rv; gchar *sexp; gboolean different_mdir; if (!maildir) { maildir = mu_msg_get_maildir (msg); different_mdir = FALSE; } else /* are we moving to a different mdir, or is it just flags? */ different_mdir = (g_strcmp0 (maildir, mu_msg_get_maildir(msg)) != 0); if (!mu_msg_move_to_maildir (msg, maildir, flags, TRUE, err)) return MU_G_ERROR_CODE (err); /* note, after mu_msg_move_to_maildir, path will be the *new* * path, and flags and maildir fields will be updated as * wel */ rv = mu_store_update_msg (store, docid, msg, err); if (rv == MU_STORE_INVALID_DOCID) { mu_util_g_set_error (err, MU_ERROR_XAPIAN, "failed to store updated message"); print_and_clear_g_error (err); } sexp = mu_msg_to_sexp (msg, docid, NULL, MU_MSG_OPTION_VERIFY); /* note, the :move t thing is a hint to the frontend that it * could remove the particular header */ print_expr ("(:update %s :move %s)", sexp, different_mdir ? "t" : "nil"); g_free (sexp); return MU_OK; }
MuError with_store (store_func func, MuConfig *opts, gboolean read_only, GError **err) { MuStore *store; if (read_only) store = mu_store_new_read_only (mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), err); else store = mu_store_new_writable (mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), mu_runtime_path(MU_RUNTIME_PATH_CONTACTS), opts->rebuild, err); if (!store) return MU_G_ERROR_CODE(err); else { MuError merr; merr = func (store, opts, err); mu_store_unref (store); return merr; } }