Mercurial > hg > xemacs-beta
view lib-src/movemail.c @ 4952:19a72041c5ed
Mule-izing, various fixes related to char * arguments
-------------------- ChangeLog entries follow: --------------------
modules/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c:
* postgresql/postgresql.c (CHECK_LIVE_CONNECTION):
* postgresql/postgresql.c (print_pgresult):
* postgresql/postgresql.c (Fpq_conn_defaults):
* postgresql/postgresql.c (Fpq_connectdb):
* postgresql/postgresql.c (Fpq_connect_start):
* postgresql/postgresql.c (Fpq_result_status):
* postgresql/postgresql.c (Fpq_res_status):
Mule-ize large parts of it.
2010-01-26 Ben Wing <ben@xemacs.org>
* ldap/eldap.c (print_ldap):
* ldap/eldap.c (allocate_ldap):
Use write_ascstring().
src/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (build_ascstring):
* alloc.c (build_msg_cistring):
* alloc.c (staticpro_1):
* alloc.c (staticpro_name):
* alloc.c (staticpro_nodump_1):
* alloc.c (staticpro_nodump_name):
* alloc.c (unstaticpro_nodump_1):
* alloc.c (mcpro_1):
* alloc.c (mcpro_name):
* alloc.c (object_memory_usage_stats):
* alloc.c (common_init_alloc_early):
* alloc.c (init_alloc_once_early):
* buffer.c (print_buffer):
* buffer.c (vars_of_buffer):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.c (init_initial_directory):
* bytecode.c (invalid_byte_code):
* bytecode.c (print_compiled_function):
* bytecode.c (mark_compiled_function):
* chartab.c (print_table_entry):
* chartab.c (print_char_table):
* config.h.in:
* console-gtk.c:
* console-gtk.c (gtk_device_to_console_connection):
* console-gtk.c (gtk_semi_canonicalize_console_connection):
* console-gtk.c (gtk_canonicalize_console_connection):
* console-gtk.c (gtk_semi_canonicalize_device_connection):
* console-gtk.c (gtk_canonicalize_device_connection):
* console-stream.c (stream_init_frame_1):
* console-stream.c (vars_of_console_stream):
* console-stream.c (init_console_stream):
* console-x.c (x_semi_canonicalize_console_connection):
* console-x.c (x_semi_canonicalize_device_connection):
* console-x.c (x_canonicalize_device_connection):
* console-x.h:
* data.c (eq_with_ebola_notice):
* data.c (Fsubr_interactive):
* data.c (Fnumber_to_string):
* data.c (digit_to_number):
* device-gtk.c (gtk_init_device):
* device-msw.c (print_devmode):
* device-x.c (x_event_name):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-msw.c (handle_file_dialog_box):
* dialog-msw.c (vars_of_dialog_mswindows):
* doc.c (weird_doc):
* doc.c (Fsnarf_documentation):
* doc.c (vars_of_doc):
* dumper.c (pdump):
* dynarr.c:
* dynarr.c (Dynarr_realloc):
* editfns.c (Fuser_real_login_name):
* editfns.c (get_home_directory):
* elhash.c (print_hash_table_data):
* elhash.c (print_hash_table):
* emacs.c (main_1):
* emacs.c (vars_of_emacs):
* emodules.c:
* emodules.c (_emodules_list):
* emodules.c (Fload_module):
* emodules.c (Funload_module):
* emodules.c (Flist_modules):
* emodules.c (find_make_module):
* emodules.c (attempt_module_delete):
* emodules.c (emodules_load):
* emodules.c (emodules_doc_subr):
* emodules.c (emodules_doc_sym):
* emodules.c (syms_of_module):
* emodules.c (vars_of_module):
* emodules.h:
* eval.c (print_subr):
* eval.c (signal_call_debugger):
* eval.c (build_error_data):
* eval.c (signal_error):
* eval.c (maybe_signal_error):
* eval.c (signal_continuable_error):
* eval.c (maybe_signal_continuable_error):
* eval.c (signal_error_2):
* eval.c (maybe_signal_error_2):
* eval.c (signal_continuable_error_2):
* eval.c (maybe_signal_continuable_error_2):
* eval.c (signal_ferror):
* eval.c (maybe_signal_ferror):
* eval.c (signal_continuable_ferror):
* eval.c (maybe_signal_continuable_ferror):
* eval.c (signal_ferror_with_frob):
* eval.c (maybe_signal_ferror_with_frob):
* eval.c (signal_continuable_ferror_with_frob):
* eval.c (maybe_signal_continuable_ferror_with_frob):
* eval.c (syntax_error):
* eval.c (syntax_error_2):
* eval.c (maybe_syntax_error):
* eval.c (sferror):
* eval.c (sferror_2):
* eval.c (maybe_sferror):
* eval.c (invalid_argument):
* eval.c (invalid_argument_2):
* eval.c (maybe_invalid_argument):
* eval.c (invalid_constant):
* eval.c (invalid_constant_2):
* eval.c (maybe_invalid_constant):
* eval.c (invalid_operation):
* eval.c (invalid_operation_2):
* eval.c (maybe_invalid_operation):
* eval.c (invalid_change):
* eval.c (invalid_change_2):
* eval.c (maybe_invalid_change):
* eval.c (invalid_state):
* eval.c (invalid_state_2):
* eval.c (maybe_invalid_state):
* eval.c (wtaerror):
* eval.c (stack_overflow):
* eval.c (out_of_memory):
* eval.c (print_multiple_value):
* eval.c (issue_call_trapping_problems_warning):
* eval.c (backtrace_specials):
* eval.c (backtrace_unevalled_args):
* eval.c (Fbacktrace):
* eval.c (warn_when_safe):
* event-Xt.c (modwarn):
* event-Xt.c (modbarf):
* event-Xt.c (check_modifier):
* event-Xt.c (store_modifier):
* event-Xt.c (emacs_Xt_format_magic_event):
* event-Xt.c (describe_event):
* event-gtk.c (dragndrop_data_received):
* event-gtk.c (store_modifier):
* event-gtk.c (gtk_reset_modifier_mapping):
* event-msw.c (dde_eval_string):
* event-msw.c (Fdde_alloc_advise_item):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (FROB):
* event-msw.c (emacs_mswindows_format_magic_event):
* event-stream.c (external_debugging_print_event):
* event-stream.c (execute_help_form):
* event-stream.c (vars_of_event_stream):
* events.c (print_event_1):
* events.c (print_event):
* events.c (event_equal):
* extents.c (print_extent_1):
* extents.c (print_extent):
* extents.c (vars_of_extents):
* faces.c (print_face):
* faces.c (complex_vars_of_faces):
* file-coding.c:
* file-coding.c (print_coding_system):
* file-coding.c (print_coding_system_in_print_method):
* file-coding.c (default_query_method):
* file-coding.c (find_coding_system):
* file-coding.c (make_coding_system_1):
* file-coding.c (chain_print):
* file-coding.c (undecided_print):
* file-coding.c (gzip_print):
* file-coding.c (vars_of_file_coding):
* file-coding.c (complex_vars_of_file_coding):
* fileio.c:
* fileio.c (report_file_type_error):
* fileio.c (report_error_with_errno):
* fileio.c (report_file_error):
* fileio.c (barf_or_query_if_file_exists):
* fileio.c (vars_of_fileio):
* floatfns.c (matherr):
* fns.c (print_bit_vector):
* fns.c (Fmapconcat):
* fns.c (add_suffix_to_symbol):
* fns.c (add_prefix_to_symbol):
* frame-gtk.c:
* frame-gtk.c (Fgtk_window_id):
* frame-x.c (def):
* frame-x.c (x_cde_transfer_callback):
* frame.c:
* frame.c (Fmake_frame):
* gc.c (show_gc_cursor_and_message):
* gc.c (vars_of_gc):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate):
* glyphs-gtk.c (gtk_print_image_instance):
* glyphs-msw.c (mswindows_print_image_instance):
* glyphs-x.c (x_print_image_instance):
* glyphs-x.c (update_widget_face):
* glyphs.c (make_string_from_file):
* glyphs.c (print_image_instance):
* glyphs.c (signal_image_error):
* glyphs.c (signal_image_error_2):
* glyphs.c (signal_double_image_error):
* glyphs.c (signal_double_image_error_2):
* glyphs.c (xbm_mask_file_munging):
* glyphs.c (pixmap_to_lisp_data):
* glyphs.h:
* gui.c (gui_item_display_flush_left):
* hpplay.c (player_error_internal):
* hpplay.c (myHandler):
* intl-win32.c:
* intl-win32.c (langcode_to_lang):
* intl-win32.c (sublangcode_to_lang):
* intl-win32.c (Fmswindows_get_locale_info):
* intl-win32.c (lcid_to_locale_mule_or_no):
* intl-win32.c (mswindows_multibyte_to_unicode_print):
* intl-win32.c (complex_vars_of_intl_win32):
* keymap.c:
* keymap.c (print_keymap):
* keymap.c (ensure_meta_prefix_char_keymapp):
* keymap.c (Fkey_description):
* keymap.c (Ftext_char_description):
* lisp.h:
* lisp.h (struct):
* lisp.h (DECLARE_INLINE_HEADER):
* lread.c (Fload_internal):
* lread.c (locate_file):
* lread.c (read_escape):
* lread.c (read_raw_string):
* lread.c (read1):
* lread.c (read_list):
* lread.c (read_compiled_function):
* lread.c (init_lread):
* lrecord.h:
* marker.c (print_marker):
* marker.c (marker_equal):
* menubar-msw.c (displayable_menu_item):
* menubar-x.c (command_builder_operate_menu_accelerator):
* menubar.c (vars_of_menubar):
* minibuf.c (reinit_complex_vars_of_minibuf):
* minibuf.c (complex_vars_of_minibuf):
* mule-charset.c (Fmake_charset):
* mule-charset.c (complex_vars_of_mule_charset):
* mule-coding.c (iso2022_print):
* mule-coding.c (fixed_width_query):
* number.c (bignum_print):
* number.c (ratio_print):
* number.c (bigfloat_print):
* number.c (bigfloat_finalize):
* objects-msw.c:
* objects-msw.c (mswindows_color_to_string):
* objects-msw.c (mswindows_color_list):
* objects-tty.c:
* objects-tty.c (tty_font_list):
* objects-tty.c (tty_find_charset_font):
* objects-xlike-inc.c (xft_find_charset_font):
* objects-xlike-inc.c (endif):
* print.c:
* print.c (write_istring):
* print.c (write_ascstring):
* print.c (Fterpri):
* print.c (Fprint):
* print.c (print_error_message):
* print.c (print_vector_internal):
* print.c (print_cons):
* print.c (print_string):
* print.c (printing_unreadable_object):
* print.c (print_internal):
* print.c (print_float):
* print.c (print_symbol):
* process-nt.c (mswindows_report_winsock_error):
* process-nt.c (nt_canonicalize_host_name):
* process-unix.c (unix_canonicalize_host_name):
* process.c (print_process):
* process.c (report_process_error):
* process.c (report_network_error):
* process.c (make_process_internal):
* process.c (Fstart_process_internal):
* process.c (status_message):
* process.c (putenv_internal):
* process.c (vars_of_process):
* process.h:
* profile.c (vars_of_profile):
* rangetab.c (print_range_table):
* realpath.c (vars_of_realpath):
* redisplay.c (vars_of_redisplay):
* search.c (wordify):
* search.c (Freplace_match):
* sheap.c (sheap_adjust_h):
* sound.c (report_sound_error):
* sound.c (Fplay_sound_file):
* specifier.c (print_specifier):
* symbols.c (Fsubr_name):
* symbols.c (do_symval_forwarding):
* symbols.c (set_default_buffer_slot_variable):
* symbols.c (set_default_console_slot_variable):
* symbols.c (store_symval_forwarding):
* symbols.c (default_value):
* symbols.c (defsymbol_massage_name_1):
* symbols.c (defsymbol_massage_name_nodump):
* symbols.c (defsymbol_massage_name):
* symbols.c (defsymbol_massage_multiword_predicate_nodump):
* symbols.c (defsymbol_massage_multiword_predicate):
* symbols.c (defsymbol_nodump):
* symbols.c (defsymbol):
* symbols.c (defkeyword):
* symbols.c (defkeyword_massage_name):
* symbols.c (check_module_subr):
* symbols.c (deferror_1):
* symbols.c (deferror):
* symbols.c (deferror_massage_name):
* symbols.c (deferror_massage_name_and_message):
* symbols.c (defvar_magic):
* symeval.h:
* symeval.h (DEFVAR_SYMVAL_FWD):
* sysdep.c:
* sysdep.c (init_system_name):
* sysdll.c:
* sysdll.c (MAYBE_PREPEND_UNDERSCORE):
* sysdll.c (dll_function):
* sysdll.c (dll_variable):
* sysdll.c (dll_error):
* sysdll.c (dll_open):
* sysdll.c (dll_close):
* sysdll.c (image_for_address):
* sysdll.c (my_find_image):
* sysdll.c (search_linked_libs):
* sysdll.h:
* sysfile.h:
* sysfile.h (DEFAULT_DIRECTORY_FALLBACK):
* syswindows.h:
* tests.c (DFC_CHECK_LENGTH):
* tests.c (DFC_CHECK_CONTENT):
* tests.c (Ftest_hash_tables):
* text.c (vars_of_text):
* text.h:
* tooltalk.c (tt_opnum_string):
* tooltalk.c (tt_message_arg_ival_string):
* tooltalk.c (Ftooltalk_default_procid):
* tooltalk.c (Ftooltalk_default_session):
* tooltalk.c (init_tooltalk):
* tooltalk.c (vars_of_tooltalk):
* ui-gtk.c (Fdll_load):
* ui-gtk.c (type_to_marshaller_type):
* ui-gtk.c (Fgtk_import_function_internal):
* ui-gtk.c (emacs_gtk_object_printer):
* ui-gtk.c (emacs_gtk_boxed_printer):
* unicode.c (unicode_to_ichar):
* unicode.c (unicode_print):
* unicode.c (unicode_query):
* unicode.c (vars_of_unicode):
* unicode.c (complex_vars_of_unicode):
* win32.c:
* win32.c (mswindows_report_process_error):
* window.c (print_window):
* xemacs.def.in.in:
BASIC IDEA: Further fixing up uses of char * and CIbyte *
to reflect their actual semantics; Mule-izing some code;
redoing of the not-yet-working code to handle message translation.
Clean up code to handle message-translation (not yet working).
Create separate versions of build_msg_string() for working with
Ibyte *, CIbyte *, and Ascbyte * arguments. Assert that Ascbyte *
arguments are pure-ASCII. Make build_msg_string() be the same
as build_msg_ascstring(). Create same three versions of GETTEXT()
and DEFER_GETTEXT(). Also create build_defer_string() and
variants for the equivalent of DEFER_GETTEXT() when building a
string. Remove old CGETTEXT(). Clean up code where GETTEXT(),
DEFER_GETTEXT(), build_msg_string(), etc. was being called and
introduce some new calls to build_msg_string(), etc. Remove
GETTEXT() from calls to weird_doc() -- we assume that the
message snarfer knows about weird_doc(). Remove uses of
DEFER_GETTEXT() from error messages in sysdep.c and instead use
special comments /* @@@begin-snarf@@@ */ and /* @@@end-snarf@@@ */
that the message snarfer presumably knows about.
Create build_ascstring() and use it in many instances in place
of build_string(). The purpose of having Ascbyte * variants is
to make the code more self-documenting in terms of what sort of
semantics is expected for char * strings. In fact in the process
of looking for uses of build_string(), much improperly Mule-ized
was discovered.
Mule-ize a lot of code as described in previous paragraph,
e.g. in sysdep.c.
Make the error functions take Ascbyte * strings and fix up a
couple of places where non-pure-ASCII strings were being passed in
(file-coding.c, mule-coding.c, unicode.c). (It's debatable whether
we really need to make the error functions work this way. It
helps catch places where code is written in a way that message
translation won't work, but we may well never implement message
translation.)
Make staticpro() and friends take Ascbyte * strings instead of
raw char * strings. Create a const_Ascbyte_ptr dynarr type
to describe what's held by staticpro_names[] and friends,
create pdump descriptions for const_Ascbyte_ptr dynarrs, and
use them in place of specially-crafted staticpro descriptions.
Mule-ize certain other functions (e.g. x_event_name) by correcting
raw use of char * to Ascbyte *, Rawbyte * or another such type,
and raw use of char[] buffers to another type (usually Ascbyte[]).
Change many uses of write_c_string() to write_msg_string(),
write_ascstring(), etc.
Mule-ize emodules.c, emodules.h, sysdll.h.
Fix some un-Mule-ized code in intl-win32.c.
A comment in event-Xt.c and the limitations of the message
snarfer (make-msgfile or whatever) is presumably incorrect --
it should be smart enough to handle function calls spread over
more than one line. Clean up code in event-Xt.c that was
written awkwardly for this reason.
In config.h.in, instead of NEED_ERROR_CHECK_TYPES_INLINES,
create a more general XEMACS_DEFS_NEEDS_INLINE_DECLS to
indicate when inlined functions need to be declared in
xemacs.defs.in.in, and make use of it in xemacs.defs.in.in.
We need to do this because postgresql.c now calls qxestrdup(),
which is an inline function.
Make nconc2() and other such functions MODULE_API and put
them in xemacs.defs.in.in since postgresql.c now uses them.
Clean up indentation in lread.c and a few other places.
In text.h, document ASSERT_ASCTEXT_ASCII() and
ASSERT_ASCTEXT_ASCII_LEN(), group together the stand-in
encodings and add some more for DLL symbols, function and
variable names, etc.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Tue, 26 Jan 2010 23:22:30 -0600 |
parents | 96d5f81e234f |
children | 308d34e9f07d |
line wrap: on
line source
/* movemail foo bar -- move file foo to file bar, locking file foo. Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. This file is part of XEmacs. XEmacs 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 2, or (at your option) any later version. XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Please mail bugs and suggestions to the XEmacs maintainer. */ /* Important notice: * * You *must* coordinate the locking method used by movemail with that * used by your mail delivery agent, as well as that of the other mail * user agents on your system. movemail allows you to do this at run * time via the -m flag. Moreover, it uses a default determined by * the MAIL_LOCK_DOT, MAIL_LOCK_LOCKF, MAIL_LOCK_FLOCK, * MAIL_LOCK_LOCKING, and MAIL_LOCK_MMDF preprocessor settings. */ /* * Mike Sperber <sperber@informatik.uni-tuebingen.de> reorganized * everything that has to with locking in December 1999. */ /* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) * * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP * movemail will accept input filename arguments of the form * "po:username". This will cause movemail to open a connection to * a pop server running on $MAILHOST (environment variable). Movemail * must be setuid to root in order to work with POP. * * New module: popmail.c * Modified routines: * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ()) * after POP code. * New routines in movemail.c: * get_errmsg - return pointer to system error message * * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies) * * Move all of the POP code into a separate file, "pop.c". * Use strerror instead of get_errmsg. * */ #define NO_SHORTNAMES /* Tell config not to load remap.h */ #include <config.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <errno.h> #include "../src/sysfile.h" #include "../src/syswait.h" #ifndef WIN32_NATIVE #include "../src/systime.h" #endif #include <stdlib.h> #include <string.h> #include "getopt.h" #ifdef MAIL_USE_POP #include "pop.h" #include "../src/regex.h" #endif extern char *optarg; extern int optind, opterr; #ifndef HAVE_STRERROR char * strerror (int errnum); #endif /* HAVE_STRERROR */ #ifndef DIRECTORY_SEP #define DIRECTORY_SEP '/' #endif #ifndef IS_DIRECTORY_SEP #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) #endif #ifdef WIN32_NATIVE #undef access #undef unlink #define fork() 0 #define sys_wait(var) (*(var) = 0) /* Unfortunately, Samba doesn't seem to properly lock Unix files even though the locking call succeeds (and indeed blocks local access from other NT programs). If you have direct file access using an NFS client or something other than Samba, the locking call might work properly - make sure it does before you enable this! */ #define DISABLE_DIRECT_ACCESS #include <io.h> #endif /* WIN32_NATIVE */ #if defined (HAVE_UNISTD_H) #include <unistd.h> #endif /* unistd.h */ #ifndef F_OK #define F_OK 0 #define X_OK 1 #define W_OK 2 #define R_OK 4 #endif /* No F_OK */ #if defined (HAVE_FCNTL_H) #include <fcntl.h> #endif /* fcntl.h */ #ifdef HAVE_LOCKING #include <sys/locking.h> #endif #ifdef HAVE_MMDF extern int lk_open (), lk_close (); #endif /* Cancel substitutions made by config.h for Emacs. */ #undef open #undef read #undef write #undef close static void fatal (char *, char*); static void error (char *, char *, char *); static void usage(int); static void pfatal_with_name (char *); static void pfatal_and_delete (char *); static char *concat (char *, char *, char *); static long *xmalloc (int); #ifdef MAIL_USE_POP static int popmail (char *, char *, char *); static int pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg); static int mbx_write (char *, FILE *); static int mbx_delimit_begin (FILE *); static int mbx_delimit_end (FILE *); static struct re_pattern_buffer* compile_regex (char* regexp_pattern); static int pop_search_top (popserver server, int msgno, int lines, struct re_pattern_buffer* regexp); #endif int verbose=0; #ifdef MAIL_USE_POP int reverse=0; int keep_messages=0; struct re_pattern_buffer* regexp_pattern=0; int match_lines=10; #endif #define VERBOSE(x) if (verbose) { printf x; fflush(stdout); } struct option longopts[] = { { "inbox", required_argument, NULL, 'i' }, { "outfile", required_argument, NULL, 'o' }, #ifdef MAIL_USE_POP { "password", required_argument, NULL, 'p' }, { "reverse-pop-order", no_argument, NULL, 'x' }, { "keep-messages", no_argument, NULL, 'k' }, { "regex", required_argument, NULL, 'r' }, { "match-lines", required_argument, NULL, 'l' }, #endif { "lock-method", required_argument, NULL, 'm' }, { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'v' }, { 0 } }; #define DOTLOCKING 0 #define FLOCKING 1 #define LOCKFING 2 #define MMDF 3 #define LOCKING 4 #if defined(MAIL_LOCK_FLOCK) && defined(HAVE_FLOCK) #define DEFAULT_LOCKING FLOCKING #elif defined(MAIL_LOCK_LOCKF) && defined(HAVE_LOCKF) #define DEFAULT_LOCKING LOCKFING #elif defined(MAIL_LOCK_MMDF) && defined(HAVE_MMDF) #define DEFAULT_LOCKING MMDF #elif defined(MAIL_LOCK_LOCKING) && defined(HAVE_LOCKING) #define DEFAULT_LOCKING LOCKING #else #define DEFAULT_LOCKING DOTLOCKING #endif #ifndef DISABLE_DIRECT_ACCESS static void lock_dot(char *); #endif static void unlock_dot(char *); static int parse_lock_method(char *); static char *unparse_lock_method(int); int main (int argc, char *argv[]) { char *inname=0, *outname=0, *poppass=0; #ifndef DISABLE_DIRECT_ACCESS int indesc, outdesc; int nread; int status; #endif int lock_method = DEFAULT_LOCKING; char *maybe_lock_env; maybe_lock_env = getenv("EMACSLOCKMETHOD"); if (maybe_lock_env) { printf("maybe-lock_env: %s\n", maybe_lock_env); lock_method = parse_lock_method(maybe_lock_env); } for (;;) { #ifdef MAIL_USE_POP char* optstring = "i:o:m:p:l:r:xvhk"; #else char* optstring = "i:o:m:vh"; #endif int opt = getopt_long (argc, argv, optstring, longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 1: /* one of the standard arguments seen */ if (!inname) inname = optarg; else if (!outname) outname = optarg; else poppass = optarg; break; case 'i': /* infile */ inname = optarg; break; case 'o': /* outfile */ outname = optarg; break; #ifdef MAIL_USE_POP case 'p': /* pop password */ poppass = optarg; break; case 'k': keep_messages=1; break; case 'x': reverse = 1; break; case 'l': /* lines to match */ match_lines = atoi (optarg); break; case 'r': /* regular expression */ regexp_pattern = compile_regex (optarg); break; #endif case 'm': lock_method = parse_lock_method(optarg); break; case 'h': usage(lock_method); exit(0); case 'v': verbose = 1; break; } } while (optind < argc) { if (!inname) inname = argv[optind]; else if (!outname) outname = argv[optind]; else poppass = argv[optind]; optind++; } if (!inname || !outname) { usage(lock_method); exit(1); } #ifdef HAVE_MMDF if (lock_method == MMDF) mmdf_init (argv[0]); #endif if (*outname == 0) fatal ("Destination file name is empty", 0); VERBOSE(("checking access to output file\n")); /* Check access to output file. */ if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) pfatal_with_name (outname); /* Also check that outname's directory is writable to the real uid. */ { char *buf = (char *) xmalloc (strlen (outname) + 1); char *cp; strcpy (buf, outname); cp = buf + strlen (buf); while (cp > buf && !IS_DIRECTORY_SEP (cp[-1])) *--cp = 0; if (cp == buf) *cp++ = '.'; if (access (buf, W_OK) != 0) pfatal_with_name (buf); free (buf); } #ifdef MAIL_USE_POP if (!strncmp (inname, "po:", 3)) { int retcode = popmail (inname + 3, outname, poppass); exit (retcode); } #ifndef WIN32_NATIVE setuid (getuid ()); #endif #endif /* MAIL_USE_POP */ #ifndef DISABLE_DIRECT_ACCESS /* Check access to input file. */ if (access (inname, R_OK | W_OK) != 0) pfatal_with_name (inname); if (fork () == 0) { setuid (getuid ()); VERBOSE(("opening input file\n")); switch (lock_method) { case DOTLOCKING: indesc = open (inname, O_RDONLY); break; #ifdef HAVE_LOCKF case LOCKFING: indesc = open (inname, O_RDWR); break; #endif #ifdef HAVE_FLOCK case FLOCKING: indesc = open (inname, O_RDWR); break; #endif #ifdef HAVE_LOCKING case LOCKING: indesc = open (inname, O_RDWR); break; #endif #ifdef HAVE_MMDF case MMDF: indesc = lk_open (inname, O_RDONLY, 0, 0, 10); break; #endif default: abort(); } if (indesc < 0) pfatal_with_name (inname); #ifdef HAVE_UMASK /* In case movemail is setuid to root, make sure the user can read the output file. */ umask (umask (0) & 0333); #endif outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); if (outdesc < 0) pfatal_with_name (outname); VERBOSE(("locking input file\n")); switch (lock_method) { #ifdef HAVE_LOCKF case LOCKFING: if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); break; #endif #ifdef HAVE_FLOCK case FLOCKING: if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); break; #endif #ifdef HAVE_LOCKING case LOCKING: if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname); break; #endif case DOTLOCKING: lock_dot(inname); break; } VERBOSE(("copying input file to output file\n")); { char buf[1024]; while (1) { nread = read (indesc, buf, sizeof buf); if (nread != write (outdesc, buf, nread)) { int saved_errno = errno; unlink (outname); errno = saved_errno; pfatal_with_name (outname); } if (nread < (int) sizeof (buf)) break; } } #ifdef HAVE_FSYNC if (fsync (outdesc) < 0) pfatal_and_delete (outname); #endif /* Check to make sure no errors before we zap the inbox. */ if (close (outdesc) != 0) pfatal_and_delete (outname); VERBOSE(("deleting or truncating input file\n")); switch (lock_method) { case LOCKFING: case FLOCKING: case LOCKING: #ifdef HAVE_FTRUNCATE ftruncate (indesc, 0L); #else close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); #endif close (indesc); break; #ifdef HAVE_MMDF case MMDF: lk_close (indesc, 0, 0, 0); break; #endif case DOTLOCKING: creat (inname, 0600); break; } exit (0); } wait (&status); if (!WIFEXITED (status)) exit (1); else if (WEXITSTATUS (status) != 0) exit (WEXITSTATUS (status)); if (lock_method == DOTLOCKING) unlock_dot(inname); #endif /* not DISABLE_DIRECT_ACCESS */ return 0; } static void usage(int lock_method) { printf ("Usage: movemail [-rvxkh] [-l lines ] [-m method ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); printf("where method is one of: dot"); #ifdef HAVE_LOCKF printf(", lockf"); #endif #ifdef HAVE_FLOCK printf(", flock"); #endif #ifdef HAVE_MMDF printf(", mmdf"); #endif #ifdef HAVE_LOCKING printf(", locking"); #endif printf("\nDefault is: %s\n", unparse_lock_method(lock_method)); } static char * unparse_lock_method(int lock_method) { switch (lock_method) { case DOTLOCKING: return "dot"; case FLOCKING: return "flock"; case LOCKFING: return "lockf"; case LOCKING: return "locking"; case MMDF: return "mmdf"; default: abort();return 0; } } static int parse_lock_method(char *method_name) { if (!strcmp("dot", method_name) || !strcmp("file", method_name)) return DOTLOCKING; #ifdef HAVE_LOCKF else if (!strcmp("lockf", method_name)) return LOCKFING; #endif #ifdef HAVE_FLOCK else if (!strcmp("flock", method_name)) return FLOCKING; #endif #ifdef HAVE_MMDF else if (!strcmp("mmdf", method_name)) return MMDF; #endif #ifdef HAVE_LOCKING else if (!strcmp("locking", method_name)) return LOCKING; #endif else fatal("invalid lock method: %s", method_name); return 0; /* unreached */ } static char * dot_filename(char *filename) { return concat (filename, ".lock", ""); } static char *dotlock_filename = NULL; #ifndef DISABLE_DIRECT_ACCESS static void lock_dot(char *filename) { struct stat st; long now; int tem; char *lockname, *p; char *tempname; int desc; dotlock_filename = (char *) xmalloc(strlen(filename) + 1); /* Use a lock file named after our first argument with .lock appended: If it exists, the mail file is locked. */ lockname = dot_filename(filename); tempname = (char *) xmalloc (strlen (filename) + strlen ("EXXXXXX") + 1); strcpy (tempname, filename); p = tempname + strlen (tempname); while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) p--; *p = 0; strcpy (p, "EXXXXXX"); #ifndef HAVE_MKSTEMP mktemp (tempname); unlink (tempname); #endif for (;;) { /* Create the lock file, but not under the lock file name. */ /* Give up if cannot do that. */ #ifdef HAVE_MKSTEMP desc = mkstemp (tempname); #else desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); #endif if (desc < 0) { char *message = (char *) xmalloc (strlen (tempname) + 50); sprintf (message, "%s--see source file lib-src/movemail.c", tempname); pfatal_with_name (message); } close (desc); tem = link (tempname, lockname); unlink (tempname); if (tem >= 0) break; sleep (1); /* If lock file is five minutes old, unlock it. Five minutes should be good enough to cope with crashes and wedgitude, and long enough to avoid being fooled by time differences between machines. */ if (stat (lockname, &st) >= 0) { now = time (0); if (st.st_ctime < now - 300) unlink (lockname); } } strcpy(dotlock_filename, filename); } #endif /* not DISABLE_DIRECT_ACCESS */ static void unlock_dot(char *filename) { unlink(dot_filename(filename)); } static void maybe_unlock_dot(void) { if (dotlock_filename) unlock_dot(dotlock_filename); } /* Print error message and exit. */ static void fatal (char *s1, char *s2) { maybe_unlock_dot(); error (s1, s2, NULL); exit (1); } /* Print error message. `s1' is printf control string, `s2' is arg for it. */ static void error (char *s1, char *s2, char *s3) { fprintf (stderr, "movemail: "); fprintf (stderr, s1, s2, s3); fprintf (stderr, "\n"); } static void pfatal_with_name (char *name) { char *s = concat ("", strerror (errno), " for %s"); fatal (s, name); } static void pfatal_and_delete (char *name) { char *s = concat ("", strerror (errno), " for %s"); unlink (name); fatal (s, name); } /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ static char * concat (char *s1, char *s2, char *s3) { int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); char *result = (char *) xmalloc (len1 + len2 + len3 + 1); strcpy (result, s1); strcpy (result + len1, s2); strcpy (result + len1 + len2, s3); *(result + len1 + len2 + len3) = 0; return result; } /* Like malloc but get fatal error if memory is exhausted. */ static long * xmalloc (int size) { long *result = (long *) malloc (size); if (!result) fatal ("virtual memory exhausted", 0); return result; } /* This is the guts of the interface to the Post Office Protocol. */ #ifdef MAIL_USE_POP #ifndef WIN32_NATIVE #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #else #undef _WINSOCKAPI_ #include <winsock.h> #endif #include <stdio.h> #include "../src/syspwd.h" #define POP_ERROR (-1) #define POP_RETRIEVED (0) #define POP_DONE (1) char *progname; FILE *sfi; FILE *sfo; char ibuffer[BUFSIZ]; char obuffer[BUFSIZ]; char Errmsg[80]; static int popmail (char *user, char *outfile, char *password) { int nmsgs, nbytes; register int i, idx; int mbfi; short* retrieved_list; FILE *mbf; popserver server; VERBOSE(("opening server\n")); server = pop_open (0, user, password, POP_NO_GETPASS); if (! server) { error ("%s", pop_error, NULL); return (1); } VERBOSE(("stat'ing messages\n")); if (pop_stat (server, &nmsgs, &nbytes)) { error ("%s", pop_error, NULL); return (1); } if (!nmsgs) { VERBOSE(("closing server\n")); pop_close (server); return (0); } /* build a retrieved table */ retrieved_list = (short*) xmalloc (sizeof (short) * (nmsgs+1)); memset (retrieved_list, 0, sizeof (short) * (nmsgs+1)); mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); if (mbfi < 0) { pop_close (server); error ("Error in open: %s, %s", strerror (errno), outfile); return (1); } #if !defined(CYGWIN) && !defined(WIN32_NATIVE) fchown (mbfi, getuid (), (gid_t) -1); #endif if ((mbf = fdopen (mbfi, "wb")) == NULL) { pop_close (server); error ("Error in fdopen: %s", strerror (errno), NULL); close (mbfi); unlink (outfile); return (1); } for (idx = 0; idx < nmsgs; idx++) { i = reverse ? nmsgs - idx : idx + 1; VERBOSE(("checking message %d \n", i)); if (!regexp_pattern || pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) { VERBOSE(("retrieving message %d \n", i)); mbx_delimit_begin (mbf); if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) { error ("%s", Errmsg, NULL); close (mbfi); return (1); } retrieved_list[i]=1; mbx_delimit_end (mbf); fflush (mbf); if (ferror (mbf)) { error ("Error in fflush: %s", strerror (errno), NULL); pop_close (server); close (mbfi); return (1); } } } /* On AFS, a call to write only modifies the file in the local * workstation's AFS cache. The changes are not written to the server * until a call to fsync or close is made. Users with AFS home * directories have lost mail when over quota because these checks were * not made in previous versions of movemail. */ #ifdef HAVE_FSYNC if (fsync (mbfi) < 0) { error ("Error in fsync: %s", strerror (errno), NULL); return (1); } #endif if (close (mbfi) == -1) { error ("Error in close: %s", strerror (errno), NULL); return (1); } if (!keep_messages) { for (i = 1; i <= nmsgs; i++) { if (retrieved_list[i] == 1) { VERBOSE(("deleting message %d \n", i)); if (pop_delete (server, i)) { error ("%s", pop_error, NULL); pop_close (server); return (1); } } } } VERBOSE(("closing server \n")); if (pop_quit (server)) { error ("%s", pop_error, NULL); return (1); } return (0); } static int pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg) { char *line; int ret; if (pop_retrieve_first (server, msgno, &line)) { strncpy (Errmsg, pop_error, sizeof (Errmsg)); Errmsg[sizeof (Errmsg)-1] = '\0'; return (POP_ERROR); } while (! (ret = pop_retrieve_next (server, &line))) { if (! line) break; if ((*action)(line, arg) != POP_RETRIEVED) { strcpy (Errmsg, strerror (errno)); pop_close (server); return (POP_ERROR); } } if (ret) { strncpy (Errmsg, pop_error, sizeof (Errmsg)); Errmsg[sizeof (Errmsg)-1] = '\0'; return (POP_ERROR); } return (POP_RETRIEVED); } /* search the top lines of each message looking for a match */ static int pop_search_top (popserver server, int msgno, int lines, struct re_pattern_buffer* regexp) { char *line; int ret; int match = POP_DONE; if (pop_top_first (server, msgno, lines, &line)) { strncpy (Errmsg, pop_error, sizeof (Errmsg)); Errmsg[sizeof (Errmsg)-1] = '\0'; return (POP_ERROR); } while (! (ret = pop_top_next (server, &line))) { if (! line) break; /* VERBOSE (("checking %s\n", line));*/ if (match != POP_RETRIEVED) { if ((ret = re_match (regexp, line, strlen (line), 0, 0)) == -2 ) { strcpy (Errmsg, "error in regular expression"); pop_close (server); return (POP_ERROR); } else if (ret >=0) { match = POP_RETRIEVED; } } } if (ret) { strncpy (Errmsg, pop_error, sizeof (Errmsg)); Errmsg[sizeof (Errmsg)-1] = '\0'; return (POP_ERROR); } return match; } /* Do this as a macro instead of using strcmp to save on execution time. */ #define IS_FROM_LINE(a) ((a[0] == 'F') \ && (a[1] == 'r') \ && (a[2] == 'o') \ && (a[3] == 'm') \ && (a[4] == ' ')) static int mbx_write (char *line, FILE *mbf) { if (IS_FROM_LINE (line)) { if (fputc ('>', mbf) == EOF) return (POP_ERROR); } if (fputs (line, mbf) == EOF) return (POP_ERROR); if (fputc (0x0a, mbf) == EOF) return (POP_ERROR); return (POP_RETRIEVED); } static int mbx_delimit_begin (FILE *mbf) { if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) return (POP_ERROR); return (POP_RETRIEVED); } static int mbx_delimit_end (FILE *mbf) { if (putc ('\037', mbf) == EOF) return (POP_ERROR); return (POP_RETRIEVED); } /* Turn a name, which is an ed-style (but Emacs syntax) regular expression, into a real regular expression by compiling it. */ static struct re_pattern_buffer* compile_regex (char* pattern) { char *err; struct re_pattern_buffer *patbuf=0; patbuf = (struct re_pattern_buffer*) xmalloc (sizeof (struct re_pattern_buffer)); patbuf->translate = NULL; patbuf->fastmap = NULL; patbuf->buffer = NULL; patbuf->allocated = 0; err = (char*) re_compile_pattern (pattern, strlen (pattern), patbuf); if (err != NULL) { error ("%s while compiling pattern", err, NULL); return 0; } return patbuf; } #endif /* MAIL_USE_POP */ #ifndef HAVE_STRERROR char * strerror (int errnum) { extern char *sys_errlist[]; extern int sys_nerr; if (errnum >= 0 && errnum < sys_nerr) return sys_errlist[errnum]; return (char *) "Unknown error"; } #endif /* ! HAVE_STRERROR */