static MuError temp_part (MuMsg *msg, unsigned docid, unsigned index, GSList *args, GError **err) { const char *what, *param; char *path; GET_STRING_OR_ERROR_RETURN (args, "what", &what, err); param = get_string_from_args (args, "param", TRUE, NULL); path = mu_msg_part_get_cache_path (msg, MU_MSG_OPTION_NONE, index, err); if (!path) print_and_clear_g_error (err); else if (!mu_msg_part_save (msg, MU_MSG_OPTION_USE_EXISTING, path, index, err)) print_and_clear_g_error (err); else { gchar *escpath; escpath = mu_str_escape_c_literal (path, FALSE); if (param) { char *escparam; escparam = mu_str_escape_c_literal (param, FALSE); print_expr ("(:temp \"%s\"" " :what \"%s\"" " :docid %u" " :param \"%s\""")", escpath, what, docid, escparam); g_free (escparam); } else print_expr ("(:temp \"%s\" :what \"%s\" :docid %u)", escpath, what, docid); g_free (escpath); } g_free (path); return MU_OK; }
/* * 'find' finds a list of messages matching some query, and takes a * parameter 'query' with the search query, and (optionally) a * parameter 'maxnum' with the maximum number of messages to return. * * returns: * => list of s-expressions, each describing a message => * (:found <number of found messages>) */ static MuError cmd_find (ServerContext *ctx, GSList *args, GError **err) { MuMsgIter *iter; unsigned foundnum; int maxnum; gboolean threads, reverse; MuMsgFieldId sortfield; const char *querystr; GET_STRING_OR_ERROR_RETURN (args, "query", &querystr, err); if (get_find_params (args, &threads, &sortfield, &reverse, &maxnum, err) != MU_OK) { print_and_clear_g_error (err); return MU_OK; } /* note: when we're threading, we get *all* matching messages, * and then only return maxnum; this is so that we maximimize * the change of all messages in a thread showing up */ iter = mu_query_run (ctx->query, querystr, threads, sortfield, reverse, threads ? -1 : maxnum, err); if (!iter) { print_and_clear_g_error (err); return MU_OK; } /* before sending new results, send an 'erase' message, so the * frontend knows it should erase the headers buffer. this * will ensure that the output of two finds will not be * mixed. */ print_expr ("(:erase t)"); foundnum = print_sexps (iter, threads, maxnum > 0 ? maxnum : G_MAXINT32); print_expr ("(:found %u)", foundnum); mu_msg_iter_destroy (iter); return MU_OK; }
/* 'view' gets a full (including body etc.) sexp for some message, * identified by either docid: or msgid:; return a (:view <sexp>) */ static MuError cmd_view (ServerContext *ctx, GSList *args, GError **err) { MuMsg *msg; const gchar *path; char *sexp; MuMsgOptions opts; unsigned docid; opts = get_view_msg_opts (args); /* when 'path' is specified, get the message at path */ path = get_string_from_args (args, "path", FALSE, NULL); if (path) { docid = 0; msg = mu_msg_new_from_file (path, NULL, err); } else { docid = determine_docid (ctx->query, args, err); if (docid == MU_STORE_INVALID_DOCID) { print_and_clear_g_error (err); return MU_OK; } msg = mu_store_get_msg (ctx->store, docid, err); } if (!msg) { print_and_clear_g_error (err); return MU_OK; } sexp = mu_msg_to_sexp (msg, docid, NULL, opts); mu_msg_unref (msg); print_expr ("(:view %s)\n", sexp); g_free (sexp); return MU_OK; }
/* 'mkdir' attempts to create a maildir directory at 'path:'; sends an * (:info mkdir ...) message when it succeeds */ static MuError cmd_mkdir (ServerContext *ctx, GSList *args, GError **err) { const char *path; GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); if (!mu_maildir_mkdir (path, 0755, FALSE, err)) print_and_clear_g_error (err); else print_expr ("(:info mkdir :message \"%s has been created\")", path); return MU_OK; }
/* 'compose' produces the un-changed *original* message sexp (ie., the message * to reply to, forward or edit) for a new message to compose). It takes two * parameters: 'type' with the compose type (either reply, forward or * edit/resend), and 'docid' for the message to reply to. Note, type:new does * not have an original message, and therefore does not need a docid * * In returns a (:compose <type> [:original <original-msg>] [:include] ) * message (detals: see code below) * * Note ':include' t or nil determines whether to include attachments */ static MuError cmd_compose (ServerContext *ctx, GHashTable *args, GError **err) { const gchar *typestr; char *sexp, *atts; unsigned ctype; MuMsgOptions opts; opts = get_encrypted_msg_opts (args); GET_STRING_OR_ERROR_RETURN (args, "type", &typestr, err); ctype = compose_type (typestr); if (ctype == INVALID_TYPE) { print_error (MU_ERROR_IN_PARAMETERS, "invalid type to compose"); return MU_OK; } if (ctype == REPLY || ctype == FORWARD || ctype == EDIT || ctype == RESEND) { MuMsg *msg; const char *docidstr; GET_STRING_OR_ERROR_RETURN (args, "docid", &docidstr, err); msg = mu_store_get_msg (ctx->store, atoi(docidstr), err); if (!msg) { print_and_clear_g_error (err); return MU_OK; } sexp = mu_msg_to_sexp (msg, atoi(docidstr), NULL, opts); atts = (ctype == FORWARD) ? include_attachments (msg, opts) : NULL; mu_msg_unref (msg); } else atts = sexp = NULL; print_expr ("(:compose %s :original %s :include %s)", typestr, sexp ? sexp : "nil", atts ? atts : "nil"); g_free (sexp); g_free (atts); return MU_OK; }
/* 'ping' takes no parameters, and provides information about this mu * server using a (:pong ...) message (details: see code below) */ static MuError cmd_ping (ServerContext *ctx, GSList *args, GError **err) { unsigned doccount; doccount = mu_store_count (ctx->store, err); if (doccount == (unsigned)-1) return print_and_clear_g_error (err); print_expr ("(:pong \"" PACKAGE_NAME "\" " " :props (" #ifdef BUILD_CRYPTO " :crypto t " #endif /*BUILD_CRYPTO*/ " :version \"" VERSION "\" " " :doccount %u))",doccount); return MU_OK; }
/* 'ping' takes no parameters, and provides information about this mu * server using a (:pong ...) message (details: see code below) */ static MuError cmd_ping (ServerContext *ctx, GSList *args, GError **err) { unsigned doccount; doccount = mu_store_count (ctx->store, err); if (doccount == (unsigned)-1) return print_and_clear_g_error (err); print_expr ("(:pong \"" PACKAGE_NAME "\" " " :props (:crypto %s :guile %s " " :version \"" VERSION "\" " " :doccount %u))", mu_util_supports (MU_FEATURE_CRYPTO) ? "t" : "nil", mu_util_supports (MU_FEATURE_GUILE|MU_FEATURE_GNUPLOT) ? "t" : "nil", doccount); return MU_OK; }
/* 'add' adds a message to the database, and takes two parameters: * 'path', which is the full path to the message, and 'maildir', which * is the maildir this message lives in (e.g. "/inbox"). response with * an (:info ...) message with information about the newly added * message (details: see code below) */ static MuError cmd_add (ServerContext *ctx, GSList *args, GError **err) { unsigned docid; const char *maildir, *path; GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); GET_STRING_OR_ERROR_RETURN (args, "maildir", &maildir, err); docid = mu_store_add_path (ctx->store, path, maildir, err); if (docid == MU_STORE_INVALID_DOCID) print_and_clear_g_error (err); else { gchar *escpath; escpath = mu_str_escape_c_literal (path, TRUE); print_expr ("(:info add :path %s :docid %u)", escpath, docid); g_free (escpath); } return MU_OK; }
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; }
static MuError save_part (MuMsg *msg, unsigned docid, unsigned index, GSList *args, GError **err) { gboolean rv; const gchar *path; gchar *escpath; GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); rv = mu_msg_part_save (msg, MU_MSG_OPTION_OVERWRITE, path, index, err); if (!rv) { print_and_clear_g_error (err); return MU_OK; } escpath = mu_str_escape_c_literal (path, FALSE); print_expr ("(:info save :message \"%s has been saved\")", escpath); g_free (escpath); return MU_OK; }