/* elmo - ELectronic Mail Operator Copyright (C) 2003, 2004 rzyjontko 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; version 2. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ---------------------------------------------------------------------- User-invoked functions are kept in exec_table.t file. This module contains routines used to execute them. */ /**************************************************************************** * IMPLEMENTATION HEADERS ****************************************************************************/ #include #include #include #include "exec.h" #include "abook.h" #include "attach.h" #include "bayes.h" #include "box_selection.h" #include "cmd.h" #include "choose.h" #include "error.h" #include "fetch.h" #include "folder.h" #include "mailreader.h" #include "sender.h" #include "xmalloc.h" #include "help.h" #include "gettext.h" #include "mybox.h" #include "wrapbox.h" #include "read.h" #include "interface.h" #include "debug.h" #include "smtp.h" #include "stats.h" #include "pgp.h" #include "select.h" #include "rarray.h" #include "pop.h" /**************************************************************************** * IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS ****************************************************************************/ #define MAX(a,b) ((a>b)?(a):(b)) #define FUN_COUNT (sizeof (fun_table) / sizeof (exec_t)) /**************************************************************************** * IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES ****************************************************************************/ struct interval { struct interval *next; exec_t *exec; time_t last; int period; }; /**************************************************************************** * IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID) ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE DATA ****************************************************************************/ static exec_t fun_table[] = { #include "exec_table.t" }; static rarray_t *macros = NULL; static exec_t *macro = NULL; static int size = 0; static int count = 0; static exec_t **table = NULL; static char *default_description = NULL; static struct interval *interval_hooks; static time_t last_user_action; /**************************************************************************** * INTERFACE DATA ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTIONS ****************************************************************************/ static int exec_cmp (const void *a, const void *b) { exec_t *aa = (exec_t *) a; exec_t *bb = (exec_t *) b; return strcmp (aa->name, bb->name); } static void execute (exec_t *exec) { if (exec->fun) exec->fun (); hook_execute (exec->hook); } static void destroy_exec (exec_t *exec) { if (exec->hook){ hook_destroy (exec->hook); xfree (exec->hook); } } static void table_resize (void) { if (count < size) return; size *= 2; table = xrealloc (table, size * sizeof (exec_t *)); } static void table_add (void) { int lbound = 0; int rbound = count; int index; int ret; while (rbound > lbound){ index = (rbound + lbound) / 2; ret = strcmp (macro->name, table[index]->name); if (ret == 0){ error_ (0, _("function or macro %s already exists"), macro->name); return; } if (ret < 0) rbound = ((index == rbound) ? rbound - 1 : index); else lbound = ((index == lbound) ? lbound + 1 : index); } memmove (table + lbound + 1, table + lbound, (count - lbound) * sizeof (exec_t *)); table[lbound] = macro; count++; } static void destroy_macros (void) { int i; exec_t *macro; if (macros == NULL) return; for (i = 0; i < macros->count; i++){ macro = (exec_t *) macros->array[i]; if (macro->desc != default_description) xfree (macro->desc); xfree (macro->name); destroy_exec (macro); xfree (macro); } rarray_destroy (macros); macros = NULL; } static void destroy_interval (struct interval *si) { if (si == NULL) return; destroy_interval (si->next); xfree (si); } static void execute_interval (struct interval *si, time_t now) { time_t last; if (si == NULL) return; execute_interval (si->next, now); last = MAX (last_user_action, si->last); if (now - last < 60 * si->period) return; si->last = now; execute (si->exec); } static void timeout_handler (int zero) { static int tick = 0; if (tick == 3000){ tick = 0; execute_interval (interval_hooks, time (NULL)); } else { tick++; } } /**************************************************************************** * INTERFACE FUNCTIONS ****************************************************************************/ void exec_init (void) { int i; qsort (fun_table, FUN_COUNT, sizeof (exec_t), exec_cmp); size = FUN_COUNT * 3 / 2; count = FUN_COUNT; table = xmalloc (size * sizeof (exec_t *)); for (i = 0; i < FUN_COUNT; i++){ table[i] = fun_table + i; } default_description = _("user defined macro"); } void exec_post_setup (void) { last_user_action = time (NULL); cmd_add_timeout_handler (timeout_handler); } exec_t * exec_lookup (const char *name) { int lbound = 0; int rbound = count; int index; int ret; if (name == NULL) return NULL; while (rbound > lbound){ index = (rbound + lbound) / 2; ret = strcmp (name, table[index]->name); if (ret == 0){ return table[index]; } if (ret < 0) rbound = ((index == rbound) ? rbound - 1 : index); if (ret > 0) lbound = ((index == lbound) ? lbound + 1 : index); } return NULL; } exec_t * exec_lookup_fun (void (*fun)(void)) { int i; for (i = 0; i < count; i++){ if (table[i]->fun == fun) break; } if (i < count) return table[i]; return NULL; } void exec_run (exec_t *exec) { if (exec) execute (exec); } void exec_run_name (char *name) { exec_t *exec; if (name == NULL || *name == '\0' || *name == '\n') return; exec = exec_lookup (name); if (exec) execute (exec); else error_ (0, _("There is no such function: %s"), name); } void exec_free_resources (void) { int i; for (i = 0; i < FUN_COUNT; i++){ destroy_exec (fun_table + i); } if (table) xfree (table); table = NULL; destroy_macros (); destroy_interval (interval_hooks); } rstring_t * exec_get_functions (const char *prefix) { int off = 0; int i = 0; rstring_t *result; while (prefix[off]){ while (i < count && prefix[off] > table[i]->name[off]) i++; if (i == count) return NULL; if (prefix[off] != table[i]->name[off]) return NULL; off++; } off--; result = rstring_create (); while (i < count && strstr (table[i]->name, prefix) == table[i]->name){ rstring_add (result, table[i]->name); i++; } return result; } void exec_new_macro (const char *name) { macro = xmalloc (sizeof (exec_t)); macro->name = xstrdup (name); macro->fun = NULL; macro->hook = NULL; macro->desc = default_description; } void exec_macro_comment (char *comment) { macro->desc = comment; } void exec_macro_add_hook (const char *fun) { exec_t *exec; exec = exec_lookup (fun); if (exec == NULL){ error_ (0, _("undefined function %s"), fun); return; } if (exec->fun){ macro->hook = hook_add (macro->hook, exec->fun); } else { macro->hook = hook_copy (macro->hook, exec->hook); } } void exec_macro_add_prog (char *prog) { macro->hook = hook_add_prog (macro->hook, prog); } void exec_macro_commit (void) { if (macros == NULL) macros = rarray_create (); rarray_add (macros, macro); table_resize (); table_add (); macro = NULL; } void exec_register_timeout_hook (int interval, const char *fun) { struct interval *si; exec_t *exec; exec = exec_lookup (fun); if (exec == NULL){ error_ (0, _("There is no such function: %s"), fun); return; } si = xmalloc (sizeof (struct interval)); si->exec = exec; si->last = time (NULL); si->period = interval; si->next = interval_hooks; interval_hooks = si; } void exec_update_last_user_action (void) { last_user_action = time (NULL); } /**************************************************************************** * INTERFACE CLASS BODIES ****************************************************************************/ /**************************************************************************** * * END MODULE exec.c * ****************************************************************************/