Merge branch 'procmule'
This commit is contained in:
@ -271,6 +271,7 @@ toys/Makefile
|
||||
toys/mug/Makefile
|
||||
toys/mug2/Makefile
|
||||
toys/muile/Makefile
|
||||
toys/procmule/Makefile
|
||||
man/Makefile
|
||||
m4/Makefile
|
||||
contrib/Makefile
|
||||
|
||||
@ -36,6 +36,8 @@ libmuguile_la_SOURCES= \
|
||||
mu-guile-msg.h \
|
||||
mu-guile-store.c \
|
||||
mu-guile-store.h \
|
||||
mu-guile-log.c \
|
||||
mu-guile-log.h \
|
||||
mu-guile-common.c \
|
||||
mu-guile-common.h
|
||||
|
||||
@ -45,7 +47,8 @@ libmuguile_la_LIBADD= \
|
||||
|
||||
XFILES= \
|
||||
mu-guile-msg.x \
|
||||
mu-guile-store.x
|
||||
mu-guile-store.x \
|
||||
mu-guile-log.x
|
||||
|
||||
BUILT_SOURCES=$(XFILES)
|
||||
|
||||
|
||||
@ -21,6 +21,9 @@
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
|
||||
#include "mu-guile-common.h"
|
||||
#include "mu-guile-store.h"
|
||||
#include "mu-guile-msg.h"
|
||||
#include "mu-guile-log.h"
|
||||
|
||||
void
|
||||
mu_guile_error (const char *func_name, int status,
|
||||
@ -45,6 +48,15 @@ mu_guile_g_error (const char *func_name, GError *err)
|
||||
|
||||
|
||||
|
||||
void
|
||||
mu_guile_init (void)
|
||||
{
|
||||
scm_with_guile (&mu_guile_msg_init, NULL);
|
||||
scm_with_guile (&mu_guile_store_init, NULL);
|
||||
scm_with_guile (&mu_guile_log_init, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* backward compat for pre-2.x guile - note, this will fail miserably
|
||||
* if you don't use a UTF8 locale
|
||||
|
||||
@ -17,8 +17,8 @@
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __MU_GUILE_UTILS_H__
|
||||
#define __MU_GUILE_UTILS_H__
|
||||
#ifndef __MU_GUILE_COMMON_H__
|
||||
#define __MU_GUILE_COMMON_H__
|
||||
|
||||
#include <libguile.h>
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
*
|
||||
* output an error
|
||||
*
|
||||
* @param func_name
|
||||
* @param status
|
||||
@ -50,6 +50,14 @@ void mu_guile_error (const char *func_name, int status,
|
||||
*/
|
||||
void mu_guile_g_error (const char *func_name, GError *err);
|
||||
|
||||
|
||||
/**
|
||||
* initialize the mu guile modules
|
||||
*
|
||||
*/
|
||||
void mu_guile_init (void);
|
||||
|
||||
|
||||
/* compatibility functions for old guile */
|
||||
#if HAVE_PRE2_GUILE
|
||||
SCM scm_from_utf8_string (const char* str);
|
||||
@ -58,5 +66,5 @@ char* scm_to_utf8_string (SCM scm);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /*__MU_GUILE_UTILS_H__*/
|
||||
#endif /*__MU_GUILE_COMMON_H__*/
|
||||
|
||||
|
||||
96
libmuguile/mu-guile-log.c
Normal file
96
libmuguile/mu-guile-log.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
** Copyright (C) 2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify it
|
||||
** under the terms of the GNU General Public License as published by the
|
||||
** Free Software Foundation; either version 3, 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
|
||||
** MERCHANTABILITY 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "mu-guile-common.h"
|
||||
#include "mu-guile-log.h"
|
||||
|
||||
enum _LogType {
|
||||
LOG_INFO,
|
||||
LOG_WARNING,
|
||||
LOG_CRITICAL
|
||||
};
|
||||
typedef enum _LogType LogType;
|
||||
|
||||
|
||||
static SCM
|
||||
write_log (LogType logtype, SCM FRM, SCM ARGS)
|
||||
#define FUNC_NAME __FUNCTION__
|
||||
{
|
||||
SCM str;
|
||||
|
||||
SCM_ASSERT (scm_is_string(FRM), FRM, SCM_ARG1, "<write_log>");
|
||||
SCM_VALIDATE_REST_ARGUMENT(ARGS);
|
||||
|
||||
str = scm_simple_format (SCM_BOOL_F, FRM, ARGS);
|
||||
|
||||
if (scm_is_string (str)) {
|
||||
|
||||
gchar *output;
|
||||
output = scm_to_utf8_string (str);
|
||||
|
||||
switch (logtype) {
|
||||
case LOG_INFO: g_message ("%s", output); break;
|
||||
case LOG_WARNING: g_warning ("%s", output); break;
|
||||
case LOG_CRITICAL: g_critical ("%s", output); break;
|
||||
}
|
||||
}
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
|
||||
#undef FUNC_NAME
|
||||
}
|
||||
|
||||
|
||||
SCM_DEFINE (log_info, "mu:log:info", 1, 0, 1, (SCM FRM, SCM ARGS),
|
||||
"log some message using a list of ARGS applied to FRM "
|
||||
"(in 'simple-format' notation).\n")
|
||||
#define FUNC_NAME s_info
|
||||
{
|
||||
return write_log (LOG_INFO, FRM, ARGS);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (log_warning, "mu:log:warning", 1, 0, 1, (SCM FRM, SCM ARGS),
|
||||
"log some warning using a list of ARGS applied to FRM (in 'simple-format' "
|
||||
"notation).\n")
|
||||
#define FUNC_NAME s_warning
|
||||
{
|
||||
return write_log (LOG_WARNING, FRM, ARGS);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (log_critical, "mu:log:critical", 1, 0, 1, (SCM FRM, SCM ARGS),
|
||||
"log some critical message using a list of ARGS applied to FRM "
|
||||
"(in 'simple-format' notation).\n")
|
||||
#define FUNC_NAME s_critical
|
||||
{
|
||||
return write_log (LOG_CRITICAL, FRM, ARGS);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
||||
void*
|
||||
mu_guile_log_init (void *data)
|
||||
{
|
||||
#include "mu-guile-log.x"
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
39
libmuguile/mu-guile-log.h
Normal file
39
libmuguile/mu-guile-log.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
** Copyright (C) 2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify it
|
||||
** under the terms of the GNU General Public License as published by the
|
||||
** Free Software Foundation; either version 3, 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
|
||||
** MERCHANTABILITY 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __MU_GUILE_LOG_H__
|
||||
#define __MU_GUILE_LOG_H__
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
/**
|
||||
* initialize mu logging functions
|
||||
*
|
||||
*/
|
||||
void *mu_guile_log_init (void *data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#endif /*__MU_GUILE_LOG_H__*/
|
||||
@ -76,6 +76,41 @@ SCM_DEFINE (msg_make_from_file, "mu:msg:make-from-file", 1, 0, 0,
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
||||
SCM_DEFINE (msg_move, "mu:msg:move-to-maildir", 2, 0, 0,
|
||||
(SCM MSG, SCM TARGETMDIR),
|
||||
"Move message to another maildir TARGETMDIR. Note that this the "
|
||||
"base-level Maildir, ie. /home/user/Maildir/archive, and must"
|
||||
" _not_ include the 'cur' or 'new' part. mu_msg_move_to_maildir "
|
||||
"will make sure that the copy is from new/ to new/ and cur/ to "
|
||||
"cur/. Also note that the target maildir must be on the same "
|
||||
"filesystem. Returns #t if it worked, #f otherwise.\n")
|
||||
#define FUNC_NAME s_msg_move
|
||||
{
|
||||
GError *err;
|
||||
MuMsgWrapper *msgwrap;
|
||||
gboolean rv;
|
||||
|
||||
SCM_ASSERT (mu_guile_scm_is_msg(MSG), MSG, SCM_ARG1, FUNC_NAME);
|
||||
SCM_ASSERT (scm_is_string (TARGETMDIR), TARGETMDIR, SCM_ARG2, FUNC_NAME);
|
||||
|
||||
msgwrap = (MuMsgWrapper*) SCM_CDR(MSG);
|
||||
|
||||
err = NULL;
|
||||
rv = mu_msg_move_to_maildir (msgwrap->_msg,
|
||||
scm_to_utf8_string (TARGETMDIR), &err);
|
||||
if (!rv && err) {
|
||||
mu_guile_g_error (FUNC_NAME, err);
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
return rv ? SCM_BOOL_T : SCM_BOOL_F;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static SCM
|
||||
scm_from_string_or_null (const char *str)
|
||||
{
|
||||
@ -146,9 +181,9 @@ SCM_DEFINE (msg_prio, "mu:msg:priority", 1, 0, 0,
|
||||
prio = mu_msg_get_prio (msgwrap->_msg);
|
||||
|
||||
switch (prio) {
|
||||
case MU_MSG_PRIO_LOW: return scm_from_locale_symbol("low");
|
||||
case MU_MSG_PRIO_NORMAL: return scm_from_locale_symbol("normal");
|
||||
case MU_MSG_PRIO_HIGH: return scm_from_locale_symbol("high");
|
||||
case MU_MSG_PRIO_LOW: return scm_from_locale_symbol("mu:low");
|
||||
case MU_MSG_PRIO_NORMAL: return scm_from_locale_symbol("mu:normal");
|
||||
case MU_MSG_PRIO_HIGH: return scm_from_locale_symbol("mu:high");
|
||||
default:
|
||||
g_return_val_if_reached (SCM_UNDEFINED);
|
||||
}
|
||||
@ -167,7 +202,12 @@ check_flag (MuMsgFlags flag, FlagData *fdata)
|
||||
{
|
||||
if (fdata->flags & flag) {
|
||||
SCM item;
|
||||
item = scm_list_1 (scm_from_locale_symbol(mu_msg_flag_name(flag)));
|
||||
char *flagsym;
|
||||
|
||||
flagsym = g_strconcat ("mu:", mu_msg_flag_name(flag), NULL);
|
||||
item = scm_list_1 (scm_from_locale_symbol(flagsym));
|
||||
g_free (flagsym);
|
||||
|
||||
fdata->lst = scm_append_x (scm_list_2(fdata->lst, item));
|
||||
}
|
||||
}
|
||||
@ -469,22 +509,22 @@ static void
|
||||
define_symbols (void)
|
||||
{
|
||||
/* message priority */
|
||||
scm_c_define ("high", scm_from_int(MU_MSG_PRIO_HIGH));
|
||||
scm_c_define ("low", scm_from_int(MU_MSG_PRIO_LOW));
|
||||
scm_c_define ("normal", scm_from_int(MU_MSG_PRIO_NORMAL));
|
||||
scm_c_define ("mu:high", scm_from_int(MU_MSG_PRIO_HIGH));
|
||||
scm_c_define ("mu:low", scm_from_int(MU_MSG_PRIO_LOW));
|
||||
scm_c_define ("mu:normal", scm_from_int(MU_MSG_PRIO_NORMAL));
|
||||
|
||||
/* message flags */
|
||||
scm_c_define ("new", scm_from_int(MU_MSG_FLAG_NEW));
|
||||
scm_c_define ("passed", scm_from_int(MU_MSG_FLAG_PASSED));
|
||||
scm_c_define ("replied", scm_from_int(MU_MSG_FLAG_REPLIED));
|
||||
scm_c_define ("seen", scm_from_int(MU_MSG_FLAG_SEEN));
|
||||
scm_c_define ("trashed", scm_from_int(MU_MSG_FLAG_TRASHED));
|
||||
scm_c_define ("draft", scm_from_int(MU_MSG_FLAG_DRAFT));
|
||||
scm_c_define ("flagged", scm_from_int(MU_MSG_FLAG_FLAGGED));
|
||||
scm_c_define ("unread", scm_from_int(MU_MSG_FLAG_UNREAD));
|
||||
scm_c_define ("signed", scm_from_int(MU_MSG_FLAG_SIGNED));
|
||||
scm_c_define ("encrypted", scm_from_int(MU_MSG_FLAG_ENCRYPTED));
|
||||
scm_c_define ("has-attach", scm_from_int(MU_MSG_FLAG_HAS_ATTACH));
|
||||
scm_c_define ("mu:new", scm_from_int(MU_MSG_FLAG_NEW));
|
||||
scm_c_define ("mu:passed", scm_from_int(MU_MSG_FLAG_PASSED));
|
||||
scm_c_define ("mu:replied", scm_from_int(MU_MSG_FLAG_REPLIED));
|
||||
scm_c_define ("mu:seen", scm_from_int(MU_MSG_FLAG_SEEN));
|
||||
scm_c_define ("mu:trashed", scm_from_int(MU_MSG_FLAG_TRASHED));
|
||||
scm_c_define ("mu:draft", scm_from_int(MU_MSG_FLAG_DRAFT));
|
||||
scm_c_define ("mu:flagged", scm_from_int(MU_MSG_FLAG_FLAGGED));
|
||||
scm_c_define ("mu:unread", scm_from_int(MU_MSG_FLAG_UNREAD));
|
||||
scm_c_define ("mu:signed", scm_from_int(MU_MSG_FLAG_SIGNED));
|
||||
scm_c_define ("mu:encrypted", scm_from_int(MU_MSG_FLAG_ENCRYPTED));
|
||||
scm_c_define ("mu:has-attach", scm_from_int(MU_MSG_FLAG_HAS_ATTACH));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -853,7 +853,8 @@ print_attr_sexp (const char* elm, const char *str, gboolean nl)
|
||||
return; /* empty: don't include */
|
||||
|
||||
esc = mu_str_escape_c_literal (str);
|
||||
g_print (" (:%s \"%s\")%s", elm, esc, nl ? "\n" : "");
|
||||
|
||||
g_print (" :%s \"%s\"%s", elm, esc, nl ? "\n" : "");
|
||||
g_free (esc);
|
||||
}
|
||||
|
||||
@ -864,14 +865,14 @@ output_sexp (MuMsgIter *iter, size_t *count)
|
||||
{
|
||||
MuMsgIter *myiter;
|
||||
size_t mycount;
|
||||
g_return_val_if_fail (iter, FALSE);
|
||||
|
||||
g_return_val_if_fail (iter, FALSE);
|
||||
|
||||
g_print ("(:messages\n");
|
||||
|
||||
for (myiter = iter, mycount = 0; !mu_msg_iter_is_done (myiter);
|
||||
mu_msg_iter_next (myiter), ++mycount) {
|
||||
|
||||
unsigned date, date_high, date_low;
|
||||
|
||||
MuMsg *msg;
|
||||
if (!(msg = mu_msg_iter_get_msg (iter, NULL))) /* don't unref */
|
||||
return FALSE;
|
||||
@ -879,19 +880,27 @@ output_sexp (MuMsgIter *iter, size_t *count)
|
||||
if (mycount != 0)
|
||||
g_print ("\n");
|
||||
|
||||
g_print (" (:message\n");
|
||||
/* emacs likes it's date in a particular way... */
|
||||
date = (unsigned) mu_msg_get_date (msg);
|
||||
date_high = date >> 16;
|
||||
date_low = date & 0xffff;
|
||||
|
||||
g_print ("(%u\n", (unsigned)mycount);
|
||||
print_attr_sexp ("from", mu_msg_get_from (msg),TRUE);
|
||||
print_attr_sexp ("to", mu_msg_get_to (msg),TRUE);
|
||||
print_attr_sexp ("cc", mu_msg_get_cc (msg),TRUE);
|
||||
print_attr_sexp ("subject", mu_msg_get_subject (msg),TRUE);
|
||||
g_print (" (:date %u)\n", (unsigned) mu_msg_get_date (msg));
|
||||
g_print (" (:size %u)\n", (unsigned) mu_msg_get_size (msg));
|
||||
g_print (" :date %u\n", date);
|
||||
g_print (" :date-high %u\n", date_high);
|
||||
g_print (" :date-low %u\n", date_low);
|
||||
g_print (" :size %u\n", (unsigned) mu_msg_get_size (msg));
|
||||
print_attr_sexp ("msgid", mu_msg_get_msgid (msg),TRUE);
|
||||
print_attr_sexp ("path", mu_msg_get_path (msg),TRUE);
|
||||
print_attr_sexp ("maildir", mu_msg_get_maildir (msg),FALSE);
|
||||
g_print (")");
|
||||
g_print (")\n;;eom");
|
||||
}
|
||||
g_print (")\n");
|
||||
|
||||
fputs ("\n", stdout);
|
||||
|
||||
if (count)
|
||||
*count = mycount;
|
||||
|
||||
@ -449,7 +449,7 @@ show_usage (gboolean noerror)
|
||||
static void
|
||||
show_version (void)
|
||||
{
|
||||
g_print ("mu (mail indexer/searcher) " VERSION "\n"
|
||||
g_print ("mu (mail indexer/searcher) version " VERSION "\n"
|
||||
"Copyright (C) 2008-2011 Dirk-Jan C. Binnema (GPLv3+)\n");
|
||||
}
|
||||
|
||||
|
||||
16
src/mu-log.c
16
src/mu-log.c
@ -165,23 +165,14 @@ log_file_backup_maybe (const char *logfile)
|
||||
|
||||
|
||||
gboolean
|
||||
mu_log_init (const char* muhome,
|
||||
gboolean backup, gboolean quiet, gboolean debug)
|
||||
mu_log_init (const char* logfile, gboolean backup,
|
||||
gboolean quiet, gboolean debug)
|
||||
{
|
||||
int fd;
|
||||
gchar *logfile;
|
||||
|
||||
/* only init once... */
|
||||
g_return_val_if_fail (!MU_LOG, FALSE);
|
||||
g_return_val_if_fail (muhome, FALSE);
|
||||
|
||||
if (!mu_util_create_dir_maybe(muhome, 0700)) {
|
||||
g_warning ("failed to init log in %s", muhome);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
logfile = g_strdup_printf ("%s%c%s", muhome,
|
||||
G_DIR_SEPARATOR, MU_LOG_FILE);
|
||||
g_return_val_if_fail (logfile, FALSE);
|
||||
|
||||
if (backup && !log_file_backup_maybe(logfile)) {
|
||||
g_warning ("failed to backup log file");
|
||||
@ -192,7 +183,6 @@ mu_log_init (const char* muhome,
|
||||
if (fd < 0)
|
||||
g_warning ("%s: open() of '%s' failed: %s", __FUNCTION__,
|
||||
logfile, strerror(errno));
|
||||
g_free (logfile);
|
||||
|
||||
if (fd < 0 || !mu_log_init_with_fd (fd, FALSE, quiet, debug)) {
|
||||
try_close (fd);
|
||||
|
||||
@ -31,7 +31,8 @@ G_BEGIN_DECLS
|
||||
/**
|
||||
* write logging information to a log file
|
||||
*
|
||||
* @param muhome the mu home directory
|
||||
* @param full path to the log file (does not have to exist yet, but
|
||||
* it's directory must)
|
||||
* @param backup if TRUE and size of log file > MU_MAX_LOG_FILE_SIZE, move
|
||||
* the log file to <log file>.old and start a new one. The .old file will overwrite
|
||||
* existing files of that name
|
||||
@ -40,7 +41,7 @@ G_BEGIN_DECLS
|
||||
*
|
||||
* @return TRUE if initialization succeeds, FALSE otherwise
|
||||
*/
|
||||
gboolean mu_log_init (const char* muhome, gboolean backup,
|
||||
gboolean mu_log_init (const char *logfile, gboolean backup,
|
||||
gboolean quiet, gboolean debug)
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
|
||||
@ -111,16 +111,16 @@ mu_msg_doc_get_num_field (MuMsgDoc *self, MuMsgFieldId mfid)
|
||||
try {
|
||||
const std::string s (self->doc().get_value(mfid));
|
||||
if (s.empty())
|
||||
return -1;
|
||||
return 0;
|
||||
else if (mfid == MU_MSG_FIELD_ID_DATE) {
|
||||
time_t t;
|
||||
t = mu_date_str_to_time_t (s.c_str(), FALSE/*utc*/);
|
||||
return static_cast<gint64>(t);
|
||||
} else
|
||||
} else {
|
||||
return static_cast<gint64>(Xapian::sortable_unserialise(s));
|
||||
}
|
||||
|
||||
} MU_XAPIAN_CATCH_BLOCK_RETURN(-1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -106,9 +106,9 @@ GSList* mu_msg_file_get_str_list_field (MuMsgFile *self,
|
||||
* @param self a valid MuMsgFile
|
||||
* @param msfid the message field id to get (must be string-based one)
|
||||
*
|
||||
* @return the numeric value, or -1
|
||||
* @return the numeric value, or -1 in case of error
|
||||
*/
|
||||
gint64 mu_msg_file_get_num_field (MuMsgFile *self, MuMsgFieldId msfid);
|
||||
gint64 mu_msg_file_get_num_field (MuMsgFile *self, MuMsgFieldId mfid);
|
||||
|
||||
|
||||
#endif /*__MU_MSG_FILE_H__*/
|
||||
|
||||
144
src/mu-msg.c
144
src/mu-msg.c
@ -669,3 +669,147 @@ mu_msg_cmp (MuMsg *m1, MuMsg *m2, MuMsgFieldId mfid)
|
||||
|
||||
return 0; /* TODO: handle lists */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
enum _MaildirType {
|
||||
MAILDIR_TYPE_CUR,
|
||||
MAILDIR_TYPE_NEW,
|
||||
MAILDIR_TYPE_OTHER
|
||||
};
|
||||
typedef enum _MaildirType MaildirType;
|
||||
|
||||
static MaildirType
|
||||
get_maildir_type (const char *path)
|
||||
{
|
||||
MaildirType mtype;
|
||||
gchar *dirname;
|
||||
|
||||
dirname = g_path_get_dirname (path);
|
||||
/* g_path_get_dirname does not specify if the name includes
|
||||
* the closing '/'... if it does, remove it */
|
||||
if (dirname[strlen(dirname) - 1 ] == G_DIR_SEPARATOR)
|
||||
dirname[strlen(dirname) - 1] = '\0';
|
||||
|
||||
if (g_str_has_suffix (dirname, "cur"))
|
||||
mtype = MAILDIR_TYPE_CUR;
|
||||
else if (g_str_has_suffix (dirname, "new"))
|
||||
mtype = MAILDIR_TYPE_CUR;
|
||||
else
|
||||
mtype = MAILDIR_TYPE_OTHER;
|
||||
|
||||
g_free (dirname);
|
||||
|
||||
return mtype;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
get_new_fullpath (const char *oldpath, const char *targetmdir,
|
||||
MaildirType mtype)
|
||||
{
|
||||
char *filename, *newfullpath;
|
||||
const char* mdirsub;
|
||||
|
||||
filename = g_path_get_basename (oldpath);
|
||||
|
||||
if (mtype == MAILDIR_TYPE_CUR)
|
||||
mdirsub = "cur";
|
||||
else if (mtype == MAILDIR_TYPE_NEW)
|
||||
mdirsub = "new";
|
||||
else {
|
||||
g_free (filename);
|
||||
g_return_val_if_reached (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newfullpath = g_strdup_printf ("%s%c%s%c%s",
|
||||
targetmdir,
|
||||
G_DIR_SEPARATOR,
|
||||
mdirsub,
|
||||
G_DIR_SEPARATOR,
|
||||
filename);
|
||||
g_free (filename);
|
||||
return newfullpath;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
msg_move (const char* oldpath, const char *newfullpath, GError **err)
|
||||
{
|
||||
if (access (oldpath, R_OK) != 0) {
|
||||
g_set_error (err, 0, MU_ERROR_FILE, "cannot read %s",
|
||||
oldpath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (access (newfullpath, F_OK) == 0) {
|
||||
g_set_error (err, 0, MU_ERROR_FILE, "%s already exists",
|
||||
newfullpath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (rename (oldpath, newfullpath) != 0) {
|
||||
g_set_error (err, 0, MU_ERROR_FILE, "error moving %s to %s",
|
||||
oldpath, newfullpath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* double check -- is the target really there? */
|
||||
if (access (newfullpath, F_OK) != 0) {
|
||||
g_set_error (err, 0, MU_ERROR_FILE, "can't find target (%s)",
|
||||
newfullpath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (access (oldpath, F_OK) == 0) {
|
||||
g_set_error (err, 0, MU_ERROR_FILE, "source is still there (%s)",
|
||||
oldpath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* move a msg to another maildir, trying to maintain 'integrity',
|
||||
* ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be
|
||||
* super-paranoid here...
|
||||
*/
|
||||
gboolean
|
||||
mu_msg_move_to_maildir (MuMsg *self, const char* targetmdir, GError **err)
|
||||
{
|
||||
const char *oldpath;
|
||||
MaildirType mtype;
|
||||
char *newfullpath;
|
||||
|
||||
g_return_val_if_fail (self, FALSE);
|
||||
g_return_val_if_fail (targetmdir, FALSE);
|
||||
g_return_val_if_fail (g_path_is_absolute(targetmdir), FALSE);
|
||||
g_return_val_if_fail (mu_util_check_dir (targetmdir, TRUE, TRUE), FALSE);
|
||||
|
||||
oldpath = mu_msg_get_path (self);
|
||||
|
||||
mtype = get_maildir_type (oldpath);
|
||||
g_return_val_if_fail (mtype==MAILDIR_TYPE_CUR||mtype==MAILDIR_TYPE_NEW,
|
||||
FALSE);
|
||||
|
||||
newfullpath = get_new_fullpath (oldpath, targetmdir, mtype);
|
||||
g_return_val_if_fail (newfullpath, FALSE);
|
||||
|
||||
if (!msg_move (oldpath, newfullpath, err))
|
||||
goto error;
|
||||
|
||||
/* update our path to new one... */
|
||||
mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_PATH, newfullpath,
|
||||
TRUE);
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
g_free (newfullpath);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
22
src/mu-msg.h
22
src/mu-msg.h
@ -357,6 +357,28 @@ const GSList* mu_msg_get_tags (MuMsg *self);
|
||||
int mu_msg_cmp (MuMsg *m1, MuMsg *m2, MuMsgFieldId mfid);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* move a message to another maildir; the function returns the full
|
||||
* path to the new message, and changes the msg to now point to the
|
||||
* new maildir
|
||||
*
|
||||
* @param msg a message with an existing file system path in an actual
|
||||
* maildir
|
||||
* @param targetmdir the target maildir; note that this the base-level
|
||||
* Maildir, ie. /home/user/Maildir/archive, and must _not_ include the
|
||||
* 'cur' or 'new' part. mu_msg_move_to_maildir will make sure that the
|
||||
* copy is from new/ to new/ and cur/ to cur/. Also note that the target
|
||||
* maildir must be on the same filesystem. *
|
||||
* @param err (may be NULL) may contain error information; note if the
|
||||
* function return FALSE, err is not set for all error condition
|
||||
* (ie. not for parameter errors)
|
||||
* @return TRUE if it worked, FALSE otherwise
|
||||
*/
|
||||
gboolean mu_msg_move_to_maildir (MuMsg *msg, const char* targetmdir,
|
||||
GError **err);
|
||||
|
||||
|
||||
enum _MuMsgContactType { /* Reply-To:? */
|
||||
MU_MSG_CONTACT_TYPE_TO = 0,
|
||||
MU_MSG_CONTACT_TYPE_FROM,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
/* -*- mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
**
|
||||
** Copyright (C) 2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
**
|
||||
@ -42,6 +42,7 @@
|
||||
struct _MuRuntimeData {
|
||||
gchar *_str[MU_RUNTIME_PATH_NUM];
|
||||
MuConfig *_config;
|
||||
gchar *_name; /* e.g., 'mu', 'mug' */
|
||||
};
|
||||
typedef struct _MuRuntimeData MuRuntimeData;
|
||||
|
||||
@ -49,8 +50,10 @@ typedef struct _MuRuntimeData MuRuntimeData;
|
||||
static gboolean _initialized = FALSE;
|
||||
static MuRuntimeData *_data = NULL;
|
||||
|
||||
static void runtime_free (void);
|
||||
static gboolean init_paths (const char* muhome, MuRuntimeData *data);
|
||||
static void runtime_free (void);
|
||||
static gboolean init_paths (const char* muhome, MuRuntimeData *data);
|
||||
static const char* runtime_path (MuRuntimePath path);
|
||||
|
||||
|
||||
static gboolean
|
||||
mu_dir_is_readable_and_writable (const char *muhome)
|
||||
@ -64,13 +67,37 @@ mu_dir_is_readable_and_writable (const char *muhome)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
init_log (const char *muhome, const char *name,
|
||||
gboolean log_stderr, gboolean quiet, gboolean debug)
|
||||
{
|
||||
gboolean rv;
|
||||
char *logpath;
|
||||
|
||||
if (log_stderr)
|
||||
return mu_log_init_with_fd (fileno(stderr), FALSE,
|
||||
quiet, debug);
|
||||
|
||||
logpath = g_strdup_printf ("%s%c%s%c%s.log",
|
||||
muhome, G_DIR_SEPARATOR,
|
||||
MU_LOG_DIRNAME, G_DIR_SEPARATOR,
|
||||
name);
|
||||
rv = mu_log_init (logpath, TRUE, quiet, debug);
|
||||
g_free (logpath);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
gboolean
|
||||
mu_runtime_init (const char* muhome_arg)
|
||||
mu_runtime_init (const char* muhome_arg, const char *name)
|
||||
{
|
||||
gchar *muhome;
|
||||
|
||||
g_return_val_if_fail (!_initialized, FALSE);
|
||||
g_return_val_if_fail (name, FALSE);
|
||||
|
||||
if (!mu_util_init_system())
|
||||
return FALSE;
|
||||
@ -85,34 +112,27 @@ mu_runtime_init (const char* muhome_arg)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!mu_log_init (muhome, TRUE, FALSE, FALSE)) {
|
||||
g_free (muhome);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_data = g_new0 (MuRuntimeData, 1);
|
||||
_data->_str[MU_RUNTIME_PATH_MUHOME] = muhome;
|
||||
init_paths (muhome, _data);
|
||||
_data->_name = g_strdup (name);
|
||||
|
||||
if (!init_log (muhome, name, FALSE, TRUE, FALSE)) {
|
||||
runtime_free ();
|
||||
g_free (muhome);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _initialized = TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
init_log (MuConfig *opts)
|
||||
{
|
||||
if (opts->log_stderr)
|
||||
return mu_log_init_with_fd (fileno(stderr), FALSE,
|
||||
opts->quiet, opts->debug);
|
||||
else
|
||||
return mu_log_init (opts->muhome, TRUE, opts->quiet,
|
||||
opts->debug);
|
||||
}
|
||||
|
||||
gboolean
|
||||
mu_runtime_init_from_cmdline (int *pargc, char ***pargv)
|
||||
mu_runtime_init_from_cmdline (int *pargc, char ***pargv, const char *name)
|
||||
{
|
||||
g_return_val_if_fail (!_initialized, FALSE);
|
||||
g_return_val_if_fail (name, FALSE);
|
||||
|
||||
if (!mu_util_init_system())
|
||||
return FALSE;
|
||||
@ -129,15 +149,19 @@ mu_runtime_init_from_cmdline (int *pargc, char ***pargv)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!init_log (_data->_config)) {
|
||||
runtime_free ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_data->_name = g_strdup (name);
|
||||
_data->_str[MU_RUNTIME_PATH_MUHOME] =
|
||||
g_strdup (_data->_config->muhome);
|
||||
init_paths (_data->_str[MU_RUNTIME_PATH_MUHOME], _data);
|
||||
|
||||
if (!init_log (runtime_path(MU_RUNTIME_PATH_MUHOME), name,
|
||||
_data->_config->log_stderr,
|
||||
_data->_config->quiet,
|
||||
_data->_config->debug)) {
|
||||
runtime_free ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _initialized = TRUE;
|
||||
}
|
||||
|
||||
@ -150,6 +174,8 @@ runtime_free (void)
|
||||
for (i = 0; i != MU_RUNTIME_PATH_NUM; ++i)
|
||||
g_free (_data->_str[i]);
|
||||
|
||||
g_free (_data->_name);
|
||||
|
||||
mu_config_destroy (_data->_config);
|
||||
|
||||
mu_log_uninit();
|
||||
@ -208,8 +234,8 @@ init_paths (const char* muhome, MuRuntimeData *data)
|
||||
G_DIR_SEPARATOR, MU_CONTACTS_FILENAME);
|
||||
|
||||
data->_str [MU_RUNTIME_PATH_LOG] =
|
||||
g_strdup_printf ("%s%c%s", muhome, G_DIR_SEPARATOR,
|
||||
MU_LOG_DIRNAME);
|
||||
g_strdup_printf ("%s%c%s", muhome,
|
||||
G_DIR_SEPARATOR, MU_LOG_DIRNAME);
|
||||
|
||||
if (!create_dirs_maybe (data))
|
||||
return FALSE;
|
||||
@ -217,6 +243,14 @@ init_paths (const char* muhome, MuRuntimeData *data)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* so we can called when _initialized is FALSE still */
|
||||
static const char*
|
||||
runtime_path (MuRuntimePath path)
|
||||
{
|
||||
return _data->_str[path];
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char*
|
||||
mu_runtime_path (MuRuntimePath path)
|
||||
@ -224,7 +258,7 @@ mu_runtime_path (MuRuntimePath path)
|
||||
g_return_val_if_fail (_initialized, NULL);
|
||||
g_return_val_if_fail (path < MU_RUNTIME_PATH_NUM, NULL);
|
||||
|
||||
return _data->_str[path];
|
||||
return runtime_path (path);
|
||||
}
|
||||
|
||||
MuConfig*
|
||||
|
||||
@ -30,10 +30,12 @@ G_BEGIN_DECLS
|
||||
* systems. To uninitialize, use mu_runtime_uninit
|
||||
*
|
||||
* @param muhome path where to find the mu home directory (typicaly, ~/.mu)
|
||||
* @param name of the main program, ie. 'mu', 'mug' or
|
||||
* 'procmule'. this influences the name of the e.g. the logfile
|
||||
*
|
||||
* @return TRUE if succeeded, FALSE in case of error
|
||||
*/
|
||||
gboolean mu_runtime_init (const char* muhome);
|
||||
gboolean mu_runtime_init (const char *muhome, const char *name);
|
||||
|
||||
|
||||
/**
|
||||
@ -44,10 +46,13 @@ gboolean mu_runtime_init (const char* muhome);
|
||||
*
|
||||
* @param ptr to the param count (typically, argc)
|
||||
* @param ptr to the params (typically, argv)
|
||||
* @param name of the main program, ie. 'mu', 'mug' or
|
||||
* 'procmule'. this influences the name of the e.g. the logfile
|
||||
*
|
||||
* @return TRUE if succeeded, FALSE in case of error
|
||||
*/
|
||||
gboolean mu_runtime_init_from_cmdline (int *pargc, char ***pargv);
|
||||
gboolean mu_runtime_init_from_cmdline (int *pargc, char ***pargv,
|
||||
const char *name);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -29,7 +29,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!mu_runtime_init_from_cmdline (&argc, &argv))
|
||||
if (!mu_runtime_init_from_cmdline (&argc, &argv, "mu"))
|
||||
return 1;
|
||||
|
||||
rv = mu_config_execute (mu_runtime_config());
|
||||
|
||||
@ -38,10 +38,10 @@ test_mu_runtime_init (void)
|
||||
|
||||
tmpdir = test_mu_common_get_random_tmpdir();
|
||||
g_assert (tmpdir);
|
||||
g_assert (mu_runtime_init (tmpdir) == TRUE);
|
||||
g_assert (mu_runtime_init (tmpdir, "test-mu-runtime") == TRUE);
|
||||
mu_runtime_uninit ();
|
||||
|
||||
g_assert (mu_runtime_init (tmpdir) == TRUE);
|
||||
g_assert (mu_runtime_init (tmpdir, "test-mu-runtime") == TRUE);
|
||||
mu_runtime_uninit ();
|
||||
|
||||
g_free (tmpdir);
|
||||
@ -62,7 +62,7 @@ test_mu_runtime_data (void)
|
||||
bmfile = g_strdup_printf ("%s%c%s", homedir,
|
||||
G_DIR_SEPARATOR, "bookmarks");
|
||||
|
||||
g_assert (mu_runtime_init (homedir) == TRUE);
|
||||
g_assert (mu_runtime_init (homedir, "test-mu-runtime") == TRUE);
|
||||
|
||||
g_assert_cmpstr (homedir, ==, mu_runtime_path (MU_RUNTIME_PATH_MUHOME));
|
||||
g_assert_cmpstr (xdir, ==, mu_runtime_path (MU_RUNTIME_PATH_XAPIANDB));
|
||||
|
||||
@ -32,3 +32,12 @@ endif
|
||||
if HAVE_GUILE
|
||||
SUBDIRS += muile
|
||||
endif
|
||||
|
||||
# for procmule, we need guile and gio
|
||||
if HAVE_GUILE
|
||||
if HAVE_GIO
|
||||
SUBDIRS += procmule
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ noinst_PROGRAMS= \
|
||||
# note, mug.cc is '.cc' only because libmu must explicitly
|
||||
# be linked as c++, not c.
|
||||
mug_SOURCES= \
|
||||
mug.cc \
|
||||
mug.c \
|
||||
mug-msg-list-view.c \
|
||||
mug-msg-list-view.h \
|
||||
mug-msg-view.h \
|
||||
@ -43,7 +43,19 @@ mug_SOURCES= \
|
||||
mug-query-bar.h \
|
||||
mug-query-bar.c \
|
||||
mug-shortcuts.c \
|
||||
mug-shortcuts.h
|
||||
mug-shortcuts.h \
|
||||
dummy.cc
|
||||
|
||||
# we need to use dummy.cc to enforce c++ linking...
|
||||
BUILT_SOURCES= \
|
||||
dummy.cc
|
||||
|
||||
dummy.cc:
|
||||
touch dummy.cc
|
||||
|
||||
DISTCLEANFILES= \
|
||||
$(BUILT_SOURCES)
|
||||
|
||||
|
||||
mug_LDADD= \
|
||||
${top_builddir}/src/libmu.la \
|
||||
|
||||
@ -369,7 +369,7 @@ main (int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
mu_runtime_init (mugdata.muhome);
|
||||
mu_runtime_init (mugdata.muhome, "mug");
|
||||
|
||||
mugshell = mug_shell (&mugdata);
|
||||
g_signal_connect (G_OBJECT (mugshell), "destroy",
|
||||
@ -28,13 +28,13 @@ INCLUDES=-I${top_srcdir} -I${top_srcdir}/src $(GTK_CFLAGS) $(WEBKIT_CFLAGS) -DIC
|
||||
AM_CFLAGS=-Wall -Wextra -Wno-unused-parameter -Wdeclaration-after-statement
|
||||
AM_CXXFLAGS=-Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
noinst_PROGRAMS= \
|
||||
noinst_PROGRAMS= \
|
||||
mug2
|
||||
|
||||
# note, mug.cc is '.cc' only because libmu must explicitly
|
||||
# be linked as c++, not c.
|
||||
mug2_SOURCES= \
|
||||
mug.cc \
|
||||
mug.c \
|
||||
mug-msg-list-view.c \
|
||||
mug-msg-list-view.h \
|
||||
mug-msg-view.h \
|
||||
@ -42,7 +42,19 @@ mug2_SOURCES= \
|
||||
mug-query-bar.h \
|
||||
mug-query-bar.c \
|
||||
mug-shortcuts.c \
|
||||
mug-shortcuts.h
|
||||
mug-shortcuts.h \
|
||||
dummy.cc
|
||||
|
||||
# we need to use dummy.cc to enforce c++ linking...
|
||||
BUILT_SOURCES= \
|
||||
dummy.cc
|
||||
|
||||
dummy.cc:
|
||||
touch dummy.cc
|
||||
|
||||
DISTCLEANFILES= \
|
||||
$(BUILT_SOURCES)
|
||||
|
||||
|
||||
mug2_LDADD= \
|
||||
${top_builddir}/src/libmu.la \
|
||||
|
||||
@ -420,7 +420,7 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
g_option_context_free (octx);
|
||||
mu_runtime_init (mugdata.muhome);
|
||||
mu_runtime_init (mugdata.muhome, "mug2");
|
||||
|
||||
mugshell = mug_shell (&mugdata);
|
||||
g_signal_connect (G_OBJECT (mugshell), "destroy",
|
||||
@ -29,7 +29,20 @@ noinst_PROGRAMS= \
|
||||
muile
|
||||
|
||||
muile_SOURCES= \
|
||||
muile.cc
|
||||
muile.c \
|
||||
dummy.cc
|
||||
|
||||
# we need to use dummy.cc to enforce c++ linking...
|
||||
BUILT_SOURCES= \
|
||||
dummy.cc
|
||||
|
||||
dummy.cc:
|
||||
touch dummy.cc
|
||||
|
||||
DISTCLEANFILES= \
|
||||
$(BUILT_SOURCES)
|
||||
|
||||
|
||||
|
||||
muile_LDFLAGS= \
|
||||
${top_builddir}/libmuguile/libmuguile.la
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
`guile'[1] is an interpreter/library for the Scheme programming language[2],
|
||||
specifically meant for extending other programs. It is, in fact, the
|
||||
official GNU language for doing so. 'muile' requires guile 2.x to get the full
|
||||
support; older versions will not support e.g. the 'mu-stats.scm' things
|
||||
support.
|
||||
|
||||
older versions will not support e.g. the 'mu-stats.scm' things
|
||||
discussed below.
|
||||
|
||||
The combination of mu + guile is called `muile', and allows you to write
|
||||
@ -53,14 +55,17 @@
|
||||
| scheme@(guile-user)> (mu:msg:subject msg)
|
||||
| $1 = "See me in bikini :-)"
|
||||
| scheme@(guile-user)> (mu:msg:flags msg)
|
||||
| $2 = (attach unread)
|
||||
| $2 = (mu:attach mu:unread)
|
||||
`----
|
||||
|
||||
and so on. Note, it's probably easiest to explore the various mu: methods
|
||||
using autocompletion; to enable that make sure you have
|
||||
|
||||
(use-modules (ice-9 readline))
|
||||
(activate-readline)
|
||||
|
||||
,----
|
||||
| (use-modules (ice-9 readline))
|
||||
| (activate-readline)
|
||||
`----
|
||||
|
||||
in your ~/.guile configuration.
|
||||
|
||||
|
||||
@ -23,9 +23,8 @@
|
||||
#include <mu-runtime.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <libguile.h>
|
||||
#include <libmuguile/mu-guile-common.h>
|
||||
#include <libmuguile/mu-guile-msg.h>
|
||||
#include <libmuguile/mu-guile-store.h>
|
||||
|
||||
struct _MuileConfig {
|
||||
const char *muhome;
|
||||
@ -97,13 +96,13 @@ main (int argc, char *argv[])
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!mu_runtime_init (opts->muhome /* NULL is okay */)) {
|
||||
if (!mu_runtime_init (opts->muhome /* NULL is okay */,
|
||||
"muile")) {
|
||||
usage ();
|
||||
goto error;
|
||||
}
|
||||
|
||||
scm_with_guile (&mu_guile_msg_init, NULL);
|
||||
scm_with_guile (&mu_guile_store_init, NULL);
|
||||
mu_guile_init (); /* initialize mu guile modules */
|
||||
|
||||
if (opts->msgpath) {
|
||||
if (!(gboolean)scm_with_guile
|
||||
49
toys/procmule/Makefile.am
Normal file
49
toys/procmule/Makefile.am
Normal file
@ -0,0 +1,49 @@
|
||||
## Copyright (C) 2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## t he Free Software Foundation; either version 3 of the 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
|
||||
## MERCHANTABILITY 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
include $(top_srcdir)/gtest.mk
|
||||
|
||||
INCLUDES=-I${top_srcdir} -I${top_srcdir}/src ${GUILE_CFLAGS} ${GLIB_CFLAGS}
|
||||
|
||||
# don't use -Werror, as it might break on other compilers
|
||||
# use -Wno-unused-parameters, because some callbacks may not
|
||||
# really need all the params they get
|
||||
AM_CFLAGS=-Wall -Wextra -Wno-unused-parameter -Wdeclaration-after-statement
|
||||
AM_CXXFLAGS=-Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
noinst_PROGRAMS= \
|
||||
procmule
|
||||
|
||||
procmule_SOURCES= \
|
||||
procmule.c \
|
||||
dummy.cc
|
||||
|
||||
# we need to use dummy.cc to enforce c++ linking...
|
||||
BUILT_SOURCES= \
|
||||
dummy.cc
|
||||
|
||||
dummy.cc:
|
||||
touch dummy.cc
|
||||
|
||||
# is this needed?
|
||||
DISTCLEANFILES= \
|
||||
$(BUILT_SOURCES)
|
||||
|
||||
procmule_LDFLAGS= \
|
||||
${top_builddir}/libmuguile/libmuguile.la \
|
||||
${top_builddir}/src/libmu.la \
|
||||
${GIO_LIBS}
|
||||
|
||||
32
toys/procmule/README
Normal file
32
toys/procmule/README
Normal file
@ -0,0 +1,32 @@
|
||||
* README
|
||||
|
||||
The toy here is called 'procmule', which tries to offer procmail[1]-like
|
||||
functionality from mu, with the procmailrc configuration language replaced
|
||||
with guile and the mu-guile-bindings.
|
||||
|
||||
Of course, I'm not arrogant enough to claim that I can replace a time-tested,
|
||||
classical Unix tool so easily. On the other hand, I'm gluing existing tools
|
||||
together.
|
||||
|
||||
Now, the big difference with procmail is that procmail is an MDA - a mail
|
||||
delivery agent. In practice, it typically reads a new e-mail message from
|
||||
standard input (it's called from the local mail daemon), and then decides what
|
||||
to do with it.
|
||||
|
||||
In contrast, procmule watches a directory (or series of directories) for
|
||||
changes - as soon as a new message appears in one of these directories,
|
||||
procmule evaluates a Guile/Scheme program (typically, ~/.mu/procmule.scm) with
|
||||
the message available as 'mu:current-msg'.
|
||||
|
||||
|
||||
|
||||
|
||||
[1] http://www.procmail.org/
|
||||
|
||||
# Local Variables:
|
||||
# mode: org; org-startup-folded: nil
|
||||
# End:
|
||||
|
||||
|
||||
|
||||
|
||||
295
toys/procmule/procmule.c
Normal file
295
toys/procmule/procmule.c
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
** Copyright (C) 2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify it
|
||||
** under the terms of the GNU General Public License as published by the
|
||||
** Free Software Foundation; either version 3, 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
|
||||
** MERCHANTABILITY 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <libmuguile/mu-guile-common.h>
|
||||
#include <libmuguile/mu-guile-msg.h>
|
||||
|
||||
#include "mu-runtime.h"
|
||||
#include "mu-util.h"
|
||||
|
||||
struct _ChildData {
|
||||
char **shell_argv;
|
||||
int shell_argc;
|
||||
};
|
||||
typedef struct _ChildData ChildData;
|
||||
|
||||
static ChildData *
|
||||
child_data_new (const char *muhome)
|
||||
{
|
||||
ChildData *data;
|
||||
|
||||
data = g_new0 (ChildData, 1);
|
||||
|
||||
data->shell_argv = g_new0 (char*,3);
|
||||
data->shell_argc = 0;
|
||||
|
||||
data->shell_argv[data->shell_argc++] = g_strdup ("procmule");
|
||||
data->shell_argv[data->shell_argc++] = g_strdup ("-s");
|
||||
data->shell_argv[data->shell_argc++] =
|
||||
g_strdup_printf ("%s%cprocmule.scm", muhome, G_DIR_SEPARATOR);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
child_data_destroy (ChildData *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
g_strfreev (data->shell_argv);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_dir_change (GFileMonitor *mon, GFile *file, GFile *other_file,
|
||||
GFileMonitorEvent event_type, ChildData *data)
|
||||
{
|
||||
gchar *path;
|
||||
|
||||
path = g_file_get_path (file);
|
||||
|
||||
/* ignore all except create events */
|
||||
if (event_type != G_FILE_MONITOR_EVENT_CREATED)
|
||||
return;
|
||||
|
||||
if (fork() == 0) { /* run guile in child */
|
||||
|
||||
mu_guile_init (); /* initialize mu guile modules */
|
||||
|
||||
if (!(gboolean)scm_with_guile
|
||||
((MuGuileFunc*)&mu_guile_msg_load_current, path)) {
|
||||
g_warning ("failed to set message in guile env");
|
||||
return;
|
||||
}
|
||||
scm_shell (data->shell_argc, data->shell_argv); /* never returns */
|
||||
}
|
||||
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static GFileMonitor*
|
||||
create_monitor (const char *path, ChildData *data)
|
||||
{
|
||||
GFile *dir;
|
||||
GFileMonitor *dirmon;
|
||||
GError *err;
|
||||
|
||||
if (!mu_util_check_dir (path, TRUE, FALSE)) {
|
||||
g_warning ("must be a readable dir: '%s'", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir = g_file_new_for_path (path);
|
||||
|
||||
err = NULL;
|
||||
dirmon = g_file_monitor_directory (dir, G_FILE_MONITOR_NONE,
|
||||
NULL, &err);
|
||||
if (!dirmon) {
|
||||
g_warning ("error adding monitor: %s", err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
g_object_unref (dir);
|
||||
|
||||
if (dirmon)
|
||||
g_signal_connect (dirmon, "changed",
|
||||
G_CALLBACK(on_dir_change), data);
|
||||
|
||||
return dirmon;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_watchlist (GSList *lst)
|
||||
{
|
||||
g_slist_foreach (lst, (GFunc)g_object_unref, NULL);
|
||||
g_slist_free (lst);
|
||||
}
|
||||
|
||||
|
||||
GSList*
|
||||
create_watchlist (char **dirs, ChildData *data)
|
||||
{
|
||||
GSList *watchlist;
|
||||
char **cur;
|
||||
|
||||
/* TODO: check for dups */
|
||||
for (watchlist = NULL, cur = dirs; cur && *cur; ++cur) {
|
||||
GFileMonitor *dirmon;
|
||||
dirmon = create_monitor (*cur, data);
|
||||
if (!dirmon) {
|
||||
destroy_watchlist (watchlist);
|
||||
return NULL;
|
||||
}
|
||||
watchlist = g_slist_prepend (watchlist, dirmon);
|
||||
}
|
||||
|
||||
return watchlist;
|
||||
}
|
||||
|
||||
|
||||
struct _PMConfig {
|
||||
char *muhome;
|
||||
char **watchdirs;
|
||||
|
||||
};
|
||||
typedef struct _PMConfig PMConfig;
|
||||
|
||||
|
||||
static void
|
||||
expand_paths (PMConfig *opts)
|
||||
{
|
||||
char **cur;
|
||||
|
||||
for (cur = opts->watchdirs; cur && *cur; ++cur)
|
||||
*cur = mu_util_dir_expand (*cur);
|
||||
|
||||
if (opts->muhome)
|
||||
opts->muhome = mu_util_dir_expand (opts->muhome);
|
||||
}
|
||||
|
||||
|
||||
static PMConfig *
|
||||
pm_config_new (int *argcp, char ***argvp)
|
||||
{
|
||||
GOptionContext *octx;
|
||||
|
||||
PMConfig *opts = g_new0 (PMConfig, 1);
|
||||
GOptionEntry entries[] = {
|
||||
{"muhome", 0, 0, G_OPTION_ARG_FILENAME, &opts->muhome,
|
||||
"specify an alternative mu directory", NULL},
|
||||
{"watch", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opts->watchdirs,
|
||||
"directory to watch (may be specified multiple times)", NULL},
|
||||
{NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}/* sentinel */
|
||||
};
|
||||
|
||||
octx = g_option_context_new ("- procmule options");
|
||||
g_option_context_add_main_entries (octx, entries, "Procmule");
|
||||
|
||||
if (!g_option_context_parse (octx, argcp, argvp, NULL)) {
|
||||
g_printerr ("error in options\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!opts->watchdirs) {
|
||||
g_printerr ("specify at least one --watch=<dir>\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
expand_paths (opts);
|
||||
|
||||
g_option_context_free (octx);
|
||||
return opts;
|
||||
|
||||
error:
|
||||
if (octx)
|
||||
g_option_context_free (octx);
|
||||
g_free (opts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pm_config_destroy (PMConfig *conf)
|
||||
{
|
||||
if (!conf)
|
||||
return;
|
||||
|
||||
g_free (conf->muhome);
|
||||
g_strfreev (conf->watchdirs);
|
||||
|
||||
g_free (conf);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
g_print ("usage: procmule [--muhome=<dir>] [--watch=<dir1>]\n");
|
||||
g_print ("also, see toys/procmule/README\n");
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
watch_dirs (char **watchdirs)
|
||||
{
|
||||
ChildData *child_data;
|
||||
GSList *watchlist;
|
||||
GMainLoop *loop;
|
||||
|
||||
child_data = child_data_new
|
||||
(mu_runtime_path(MU_RUNTIME_PATH_MUHOME));
|
||||
|
||||
watchlist = create_watchlist (watchdirs, child_data);
|
||||
if (!watchlist)
|
||||
goto error;
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
destroy_watchlist (watchlist);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
child_data_destroy (child_data);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
PMConfig *opts;
|
||||
|
||||
g_type_init ();
|
||||
g_thread_init (NULL);
|
||||
|
||||
#ifdef HAVE_PRE2_GUILE
|
||||
g_warning ("Note: pre-2.x version of guile: procmule will not function "
|
||||
"correctly unless you're using UTF-8 locale.");
|
||||
#endif /* HAVE_PRE2_GUILE */
|
||||
|
||||
opts = pm_config_new (&argc, &argv);
|
||||
if (!opts) {
|
||||
usage ();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!mu_runtime_init (opts->muhome, "procmule")) {
|
||||
usage ();
|
||||
goto error;
|
||||
}
|
||||
|
||||
watch_dirs (opts->watchdirs); /* do it! */
|
||||
mu_runtime_uninit ();
|
||||
|
||||
pm_config_destroy (opts);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pm_config_destroy (opts);
|
||||
return 1;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user