X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=mx.c;h=321ebcbd88ddc8bdc1ca490afcb543b635a8c0c6;hp=1cf70784405082ea4bfa082190eb58d708dd710b;hb=decc5c3abbd9004ced0d36059818aa9688491872;hpb=74a2265af51ce89bca845adc1d68f273c9933c13 diff --git a/mx.c b/mx.c index 1cf7078..321ebcb 100644 --- a/mx.c +++ b/mx.c @@ -14,27 +14,32 @@ #include "mutt.h" #include "mx.h" +#include "mbox.h" +#include "mh.h" #include "rfc2047.h" #include "sort.h" -#include "mailbox.h" #include "copy.h" #include "keymap.h" #include "url.h" +#include "sidebar.h" #ifdef USE_COMPRESSED #include "compress.h" #endif #ifdef USE_IMAP -#include "imap.h" +#include "imap/imap.h" +#include "imap/mx_imap.h" #endif #ifdef USE_POP -#include "pop.h" +#include "pop/pop.h" +#include "pop/mx_pop.h" #endif #ifdef USE_NNTP -#include "nntp.h" +#include "nntp/nntp.h" +#include "nntp/mx_nntp.h" #endif #ifdef BUFFY_SIZE @@ -50,6 +55,8 @@ #include "lib/mem.h" #include "lib/intl.h" #include "lib/str.h" +#include "lib/list.h" +#include "lib/debug.h" #include #include @@ -60,12 +67,13 @@ #include #include #include -#ifndef BUFFY_SIZE #include -#endif +static list2_t* MailboxFormats = NULL; +#define MX_COMMAND(idx,cmd) ((mx_t*) MailboxFormats->data[idx])->cmd +#define MX_IDX(idx) (idx >= 0 && idx < MailboxFormats->length) -#define mutt_is_spool(s) (mutt_strcmp (Spoolfile, s) == 0) +#define mutt_is_spool(s) (safe_strcmp (Spoolfile, s) == 0) #ifdef USE_DOTLOCK /* parameters: @@ -142,6 +150,31 @@ static int undotlock_file (const char *path, int fd) #endif /* USE_DOTLOCK */ +/* looks up index of type for path in MailboxFormats */ +static int mx_get_idx (const char* path) { + int i = 0, t = 0; + struct stat st; + + /* first, test all non-local folders to avoid stat() call */ + for (i = 0; i < MailboxFormats->length; i++) { + if (!MX_COMMAND(i,local)) + t = MX_COMMAND(i,mx_is_magic)(path, NULL); + if (t >= 1) + return (t-1); + } + if (stat (path, &st) == 0) { + /* if stat() succeeded, keep testing until success and + * pass stat() info so that we only need to do it once */ + for (i = 0; i < MailboxFormats->length; i++) { + if (MX_COMMAND(i,local)) + t = MX_COMMAND(i,mx_is_magic)(path, &st); + if (t >= 1) + return (t-1); + } + } + return (-1); +} + /* Args: * excl if excl != 0, request an exclusive lock * dot if dot != 0, try to dotlock the file @@ -169,7 +202,7 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout) while (fcntl (fd, F_SETLK, &lck) == -1) { struct stat sb; - dprint (1, (debugfile, "mx_lock_file(): fcntl errno %d.\n", errno)); + debug_print (1, ("fcntl errno %d.\n", errno)); if (errno != EAGAIN && errno != EACCES) { mutt_perror ("fcntl"); return (-1); @@ -305,177 +338,21 @@ void mx_unlink_empty (const char *path) close (fd); } -/* try to figure out what type of mailbox ``path'' is - * - * return values: - * M_* mailbox type - * 0 not a mailbox - * -1 error - */ - -#ifdef USE_IMAP - -int mx_is_imap (const char *p) -{ - url_scheme_t scheme; - - if (!p) - return 0; - - if (*p == '{') - return 1; - - scheme = url_check_scheme (p); - if (scheme == U_IMAP || scheme == U_IMAPS) - return 1; - - return 0; -} - -#endif - -#ifdef USE_POP -int mx_is_pop (const char *p) -{ - url_scheme_t scheme; - - if (!p) - return 0; - - scheme = url_check_scheme (p); - if (scheme == U_POP || scheme == U_POPS) - return 1; - - return 0; -} -#endif - -#ifdef USE_NNTP -int mx_is_nntp (const char *p) -{ - url_scheme_t scheme; - - if (!p) - return 0; - - scheme = url_check_scheme (p); - if (scheme == U_NNTP || scheme == U_NNTPS) - return 1; - - return 0; -} -#endif - -int mx_get_magic (const char *path) -{ - struct stat st; - int magic = 0; - char tmp[_POSIX_PATH_MAX]; - FILE *f; - -#ifdef USE_IMAP - if (mx_is_imap (path)) - return M_IMAP; -#endif /* USE_IMAP */ - -#ifdef USE_POP - if (mx_is_pop (path)) - return M_POP; -#endif /* USE_POP */ - -#ifdef USE_NNTP - if (mx_is_nntp (path)) - return M_NNTP; -#endif /* USE_NNTP */ - - if (stat (path, &st) == -1) { - dprint (1, - (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n", - path, strerror (errno), errno)); - return (-1); - } - - if (S_ISDIR (st.st_mode)) { - /* check for maildir-style mailbox */ - - snprintf (tmp, sizeof (tmp), "%s/cur", path); - if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode)) - return (M_MAILDIR); - - /* check for mh-style mailbox */ - - snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", path); - if (access (tmp, F_OK) == 0) - return (M_MH); - - snprintf (tmp, sizeof (tmp), "%s/.xmhcache", path); - if (access (tmp, F_OK) == 0) - return (M_MH); - - snprintf (tmp, sizeof (tmp), "%s/.mew_cache", path); - if (access (tmp, F_OK) == 0) - return (M_MH); - - snprintf (tmp, sizeof (tmp), "%s/.mew-cache", path); - if (access (tmp, F_OK) == 0) - return (M_MH); - - snprintf (tmp, sizeof (tmp), "%s/.sylpheed_cache", path); - if (access (tmp, F_OK) == 0) - return (M_MH); - - /* - * ok, this isn't an mh folder, but mh mode can be used to read - * Usenet news from the spool. ;-) - */ - - snprintf (tmp, sizeof (tmp), "%s/.overview", path); - if (access (tmp, F_OK) == 0) - return (M_MH); - - } - else if (st.st_size == 0) { - /* hard to tell what zero-length files are, so assume the default magic */ - if (DefaultMagic == M_MBOX || DefaultMagic == M_MMDF) - return (DefaultMagic); - else - return (M_MBOX); - } - else if ((f = fopen (path, "r")) != NULL) { -#ifndef BUFFY_SIZE - struct utimbuf times; -#endif +/* try to figure out what type of mailbox ``path'' is */ +int mx_get_magic (const char *path) { + int i = 0; - fgets (tmp, sizeof (tmp), f); - if (mutt_strncmp ("From ", tmp, 5) == 0) - magic = M_MBOX; - else if (mutt_strcmp (MMDF_SEP, tmp) == 0) - magic = M_MMDF; - safe_fclose (&f); -#ifndef BUFFY_SIZE - /* need to restore the times here, the file was not really accessed, - * only the type was accessed. This is important, because detection - * of "new mail" depends on those times set correctly. - */ - times.actime = st.st_atime; - times.modtime = st.st_mtime; - utime (path, ×); -#endif - } - else { - dprint (1, - (debugfile, - "mx_get_magic(): unable to open file %s for reading.\n", path)); - mutt_perror (path); + if (safe_strlen (path) == 0) return (-1); - } - -#ifdef USE_COMPRESSED - if (magic == 0 && mutt_can_read_compressed (path)) - return M_COMPRESSED; -#endif + if ((i = mx_get_idx (path)) >= 0) + return (MX_COMMAND(i,type)); + return (-1); +} - return (magic); +int mx_is_local (int m) { + if (!MX_IDX(m)) + return (0); + return (MX_COMMAND(m,local)); } /* @@ -502,12 +379,11 @@ int mx_set_magic (const char *s) * we use the normal access() flags. */ int mx_access (const char *path, int flags) { -#ifdef USE_IMAP - if (mx_is_imap (path)) - return imap_access (path, flags); -#endif + int i = 0; - return access (path, flags); + if ((i = mx_get_idx (path)) >= 0 && MX_COMMAND(i,mx_access)) + return (MX_COMMAND(i,mx_access)(path,flags)); + return (0); } static int mx_open_mailbox_append (CONTEXT * ctx, int flags) @@ -525,7 +401,7 @@ static int mx_open_mailbox_append (CONTEXT * ctx, int flags) #ifdef USE_IMAP - if (mx_is_imap (ctx->path)) + if (mx_get_magic (ctx->path) == M_IMAP) return imap_open_mailbox_append (ctx); #endif @@ -653,6 +529,8 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT * pctx) ctx->quiet = 1; if (flags & M_READONLY) ctx->readonly = 1; + if (flags & M_COUNT) + ctx->counting = 1; if (flags & (M_APPEND | M_NEWFOLDER)) { if (mx_open_mailbox_append (ctx, flags) != 0) { @@ -664,7 +542,8 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT * pctx) return ctx; } - ctx->magic = mx_get_magic (path); + if (!MX_IDX(ctx->magic-1)) + ctx->magic = mx_get_magic (path); #ifdef USE_COMPRESSED if (ctx->magic == M_COMPRESSED) @@ -694,42 +573,7 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT * pctx) if (!ctx->quiet) mutt_message (_("Reading %s..."), ctx->path); - switch (ctx->magic) { - case M_MH: - rc = mh_read_dir (ctx, NULL); - break; - - case M_MAILDIR: - rc = maildir_read_dir (ctx); - break; - - case M_MMDF: - case M_MBOX: - rc = mbox_open_mailbox (ctx); - break; - -#ifdef USE_IMAP - case M_IMAP: - rc = imap_open_mailbox (ctx); - break; -#endif /* USE_IMAP */ - -#ifdef USE_POP - case M_POP: - rc = pop_open_mailbox (ctx); - break; -#endif /* USE_POP */ - -#ifdef USE_NNTP - case M_NNTP: - rc = nntp_open_mailbox (ctx); - break; -#endif /* USE_NNTP */ - - default: - rc = -1; - break; - } + rc = MX_COMMAND(ctx->magic-1,mx_open_mailbox)(ctx); if (rc == 0) { if ((flags & M_NOSORT) == 0) { @@ -760,18 +604,8 @@ void mx_fastclose_mailbox (CONTEXT * ctx) if (!ctx) return; -#ifdef USE_IMAP - if (ctx->magic == M_IMAP) - imap_close_mailbox (ctx); -#endif /* USE_IMAP */ -#ifdef USE_POP - if (ctx->magic == M_POP) - pop_close_mailbox (ctx); -#endif /* USE_POP */ -#ifdef USE_NNTP - if (ctx->magic == M_NNTP) - nntp_fastclose_mailbox (ctx); -#endif /* USE_NNTP */ + if (MX_IDX(ctx->magic-1) && MX_COMMAND(ctx->magic-1,mx_fastclose_mailbox)) + MX_COMMAND(ctx->magic-1,mx_fastclose_mailbox(ctx)); if (ctx->subj_hash) hash_destroy (&ctx->subj_hash, NULL); if (ctx->id_hash) @@ -796,57 +630,14 @@ void mx_fastclose_mailbox (CONTEXT * ctx) /* save changes to disk */ static int sync_mailbox (CONTEXT * ctx, int *index_hint) { -#ifdef BUFFY_SIZE - BUFFY *tmp = NULL; -#endif int rc = -1; if (!ctx->quiet) mutt_message (_("Writing %s..."), ctx->path); - switch (ctx->magic) { - case M_MBOX: - case M_MMDF: - rc = mbox_sync_mailbox (ctx, index_hint); -#ifdef BUFFY_SIZE - tmp = mutt_find_mailbox (ctx->path); -#endif - break; - - case M_MH: - case M_MAILDIR: - rc = mh_sync_mailbox (ctx, index_hint); - break; - -#ifdef USE_IMAP - case M_IMAP: - /* extra argument means EXPUNGE */ - rc = imap_sync_mailbox (ctx, 1, index_hint); - break; -#endif /* USE_IMAP */ - -#ifdef USE_POP - case M_POP: - rc = pop_sync_mailbox (ctx, index_hint); - break; -#endif /* USE_POP */ - -#ifdef USE_NNTP - case M_NNTP: - rc = nntp_sync_mailbox (ctx); - break; -#endif /* USE_NNTP */ - } - -#if 0 - if (!ctx->quiet && !ctx->shutup && rc == -1) - mutt_error (_("Could not synchronize mailbox %s!"), ctx->path); -#endif - -#ifdef BUFFY_SIZE - if (tmp && tmp->new == 0) - mutt_update_mailbox (tmp); -#endif + if (MX_IDX(ctx->magic-1)) + /* the 1 is only of interest for IMAP and means EXPUNGE */ + rc = MX_COMMAND(ctx->magic-1,mx_sync_mailbox(ctx,1,index_hint)); #ifdef USE_COMPRESSED if (rc == 0 && ctx->compressinfo) @@ -1001,7 +792,7 @@ int mx_close_mailbox (CONTEXT * ctx, int *index_hint) /* try to use server-side copy first */ i = 1; - if (ctx->magic == M_IMAP && mx_is_imap (mbox)) { + if (ctx->magic == M_IMAP && imap_is_magic (mbox, NULL) == M_IMAP) { /* tag messages for moving, and clear old tags, if any */ for (i = 0; i < ctx->msgcount; i++) if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted @@ -1183,6 +974,9 @@ void mx_update_tables (CONTEXT * ctx, int committing) } #undef this_body ctx->msgcount = j; + + /* update sidebar count */ + sidebar_set_buffystats (ctx); } @@ -1283,6 +1077,9 @@ int mx_sync_mailbox (CONTEXT * ctx, int *index_hint) return 0; } + /* update sidebar counts */ + sidebar_set_buffystats (ctx); + /* if we haven't deleted any messages, we don't need to resort */ /* ... except for certain folder formats which need "unsorted" * sort order in order to synchronize folders. @@ -1305,28 +1102,6 @@ int mx_sync_mailbox (CONTEXT * ctx, int *index_hint) return (rc); } - -/* {maildir,mh}_open_new_message are in mh.c. */ - -int mbox_open_new_message (MESSAGE * msg, CONTEXT * dest, HEADER * hdr) -{ - msg->fp = dest->fp; - return 0; -} - -#ifdef USE_IMAP -int imap_open_new_message (MESSAGE * msg, CONTEXT * dest, HEADER * hdr) -{ - char tmp[_POSIX_PATH_MAX]; - - mutt_mktemp (tmp); - if ((msg->fp = safe_fopen (tmp, "w")) == NULL) - return (-1); - msg->path = safe_strdup (tmp); - return 0; -} -#endif - /* args: * dest destintation mailbox * hdr message being copied (required for maildir support, because @@ -1335,30 +1110,10 @@ int imap_open_new_message (MESSAGE * msg, CONTEXT * dest, HEADER * hdr) MESSAGE *mx_open_new_message (CONTEXT * dest, HEADER * hdr, int flags) { MESSAGE *msg; - int (*func) (MESSAGE *, CONTEXT *, HEADER *); ADDRESS *p = NULL; - switch (dest->magic) { - case M_MMDF: - case M_MBOX: - func = mbox_open_new_message; - break; - case M_MAILDIR: - func = maildir_open_new_message; - break; - case M_MH: - func = mh_open_new_message; - break; -#ifdef USE_IMAP - case M_IMAP: - func = imap_open_new_message; - break; -#endif - default: - dprint (1, - (debugfile, - "mx_open_new_message(): function unimplemented for mailbox type %d.\n", - dest->magic)); + if (!MX_IDX(dest->magic-1)) { + debug_print (1, ("function unimplemented for mailbox type %d.\n", dest->magic)); return (NULL); } @@ -1376,7 +1131,7 @@ MESSAGE *mx_open_new_message (CONTEXT * dest, HEADER * hdr, int flags) if (msg->received == 0) time (&msg->received); - if (func (msg, dest, hdr) == 0) { + if (MX_COMMAND(dest->magic-1,mx_open_new_message)(msg, dest, hdr) == 0) { if (dest->magic == M_MMDF) fputs (MMDF_SEP, msg->fp); @@ -1401,10 +1156,7 @@ MESSAGE *mx_open_new_message (CONTEXT * dest, HEADER * hdr, int flags) } /* check for new mail */ -int mx_check_mailbox (CONTEXT * ctx, int *index_hint, int lock) -{ - int rc; - +int mx_check_mailbox (CONTEXT * ctx, int *index_hint, int lock) { #ifdef USE_COMPRESSED if (ctx->compressinfo) return mutt_check_mailbox_compressed (ctx); @@ -1413,53 +1165,13 @@ int mx_check_mailbox (CONTEXT * ctx, int *index_hint, int lock) if (ctx) { if (ctx->locked) lock = 0; - - switch (ctx->magic) { - case M_MBOX: - case M_MMDF: - - if (lock) { - mutt_block_signals (); - if (mbox_lock_mailbox (ctx, 0, 0) == -1) { - mutt_unblock_signals (); - return M_LOCKED; - } - } - - rc = mbox_check_mailbox (ctx, index_hint); - - if (lock) { - mutt_unblock_signals (); - mbox_unlock_mailbox (ctx); - } - - return rc; - - - case M_MH: - return (mh_check_mailbox (ctx, index_hint)); - case M_MAILDIR: - return (maildir_check_mailbox (ctx, index_hint)); - -#ifdef USE_IMAP - case M_IMAP: - return (imap_check_mailbox (ctx, index_hint, 0)); -#endif /* USE_IMAP */ - -#ifdef USE_POP - case M_POP: - return (pop_check_mailbox (ctx, index_hint)); -#endif /* USE_POP */ - -#ifdef USE_NNTP - case M_NNTP: - return (nntp_check_mailbox (ctx)); -#endif /* USE_NNTP */ - } + if (MX_COMMAND(ctx->magic-1,mx_check_mailbox)) + return (MX_COMMAND(ctx->magic-1,mx_check_mailbox)(ctx, index_hint, lock)); } - dprint (1, (debugfile, "mx_check_mailbox: null or invalid context.\n")); + debug_print (1, ("null or invalid context.\n")); return (-1); + } /* return a stream pointer for a message */ @@ -1488,8 +1200,7 @@ MESSAGE *mx_open_message (CONTEXT * ctx, int msgno) if (msg->fp == NULL) { mutt_perror (path); - dprint (1, (debugfile, "mx_open_message: fopen: %s: %s (errno %d).\n", - path, strerror (errno), errno)); + debug_print (1, ("fopen: %s: %s (errno %d).\n", path, strerror (errno), errno)); FREE (&msg); } } @@ -1523,10 +1234,7 @@ MESSAGE *mx_open_message (CONTEXT * ctx, int msgno) #endif /* USE_NNTP */ default: - dprint (1, - (debugfile, - "mx_open_message(): function not implemented for mailbox type %d.\n", - ctx->magic)); + debug_print (1, ("function not implemented for mailbox type %d.\n", ctx->magic)); FREE (&msg); break; } @@ -1540,10 +1248,7 @@ int mx_commit_message (MESSAGE * msg, CONTEXT * ctx) int r = 0; if (!(msg->write && ctx->append)) { - dprint (1, - (debugfile, - "mx_commit_message(): msg->write = %d, ctx->append = %d\n", - msg->write, ctx->append)); + debug_print (1, ("msg->write = %d, ctx->append = %d\n", msg->write, ctx->append)); return -1; } @@ -1586,7 +1291,7 @@ int mx_commit_message (MESSAGE * msg, CONTEXT * ctx) if (r == 0 && (ctx->magic == M_MBOX || ctx->magic == M_MMDF) && (fflush (msg->fp) == EOF || fsync (fileno (msg->fp)) == -1)) { - mutt_perror _("Can't write message"); + mutt_perror (_("Can't write message")); r = -1; } @@ -1616,8 +1321,7 @@ int mx_close_message (MESSAGE ** msg) (*msg)->fp = NULL; if ((*msg)->path) { - dprint (1, (debugfile, "mx_close_message (): unlinking %s\n", - (*msg)->path)); + debug_print (1, ("unlinking %s\n", (*msg)->path)); unlink ((*msg)->path); FREE (&(*msg)->path); } @@ -1687,7 +1391,7 @@ void mx_update_context (CONTEXT * ctx, int new_messages) /* FREE (&h->env->supersedes); should I ? */ if (h2) { h2->superseded = 1; - if (option (OPTSCORE)) + if (!ctx->counting && option (OPTSCORE)) mutt_score_message (ctx, h2, 1); } } @@ -1695,11 +1399,13 @@ void mx_update_context (CONTEXT * ctx, int new_messages) /* add this message to the hash tables */ if (ctx->id_hash && h->env->message_id) hash_insert (ctx->id_hash, h->env->message_id, h, 0); - if (ctx->subj_hash && h->env->real_subj) - hash_insert (ctx->subj_hash, h->env->real_subj, h, 1); + if (!ctx->counting) { + if (ctx->subj_hash && h->env->real_subj) + hash_insert (ctx->subj_hash, h->env->real_subj, h, 1); - if (option (OPTSCORE)) - mutt_score_message (ctx, h, 0); + if (option (OPTSCORE)) + mutt_score_message (ctx, h, 0); + } if (h->changed) ctx->changed = 1; @@ -1713,6 +1419,8 @@ void mx_update_context (CONTEXT * ctx, int new_messages) ctx->new++; } } + /* update sidebar count */ + sidebar_set_buffystats (ctx); } /* @@ -1723,17 +1431,51 @@ void mx_update_context (CONTEXT * ctx, int new_messages) */ int mx_check_empty (const char *path) { - switch (mx_get_magic (path)) { - case M_MBOX: - case M_MMDF: - return mbox_check_empty (path); - case M_MH: - return mh_check_empty (path); - case M_MAILDIR: - return maildir_check_empty (path); - default: - errno = EINVAL; - return -1; + int i = 0; + if ((i = mx_get_idx (path)) >= 0 && MX_COMMAND(i,mx_check_empty)) + return (MX_COMMAND(i,mx_check_empty)(path)); + errno = EINVAL; + return (-1); +} + +int mx_acl_check (CONTEXT* ctx, int flag) { + if (!ctx || !MX_IDX(ctx->magic-1)) + return (0); + /* if no acl_check defined for module, assume permission is granted */ + if (!MX_COMMAND(ctx->magic-1,mx_acl_check)) + return (1); + return (MX_COMMAND(ctx->magic-1,mx_acl_check)(ctx,flag)); +} + +void mx_init (void) { +#ifdef DEBUG + int i = 0; +#endif + list_push_back (&MailboxFormats, (void*) mbox_reg_mx ()); + list_push_back (&MailboxFormats, (void*) mmdf_reg_mx ()); + list_push_back (&MailboxFormats, (void*) mh_reg_mx ()); + list_push_back (&MailboxFormats, (void*) maildir_reg_mx ()); +#ifdef USE_IMAP + list_push_back (&MailboxFormats, (void*) imap_reg_mx ()); +#endif +#ifdef USE_POP + list_push_back (&MailboxFormats, (void*) pop_reg_mx ()); +#endif +#ifdef USE_NNTP + list_push_back (&MailboxFormats, (void*) nntp_reg_mx ()); +#endif +#ifdef USE_COMPRESSED + list_push_back (&MailboxFormats, (void*) compress_reg_mx ()); +#endif +#ifdef DEBUG + /* check module registration for completeness with debug versions */ +#define EXITWITHERR(m) do { fprintf(stderr, "error: incomplete mx module: %s is missing for type %i\n",m,i);exit(1); } while (0) + for (i = 0; i < MailboxFormats->length; i++) { + if (MX_COMMAND(i,type) < 1) EXITWITHERR("type"); + if (!MX_COMMAND(i,mx_is_magic)) EXITWITHERR("mx_is_magic"); + if (!MX_COMMAND(i,mx_open_mailbox)) EXITWITHERR("mx_open_mailbox"); +/* if (!MX_COMMAND(i,mx_sync_mailbox)) EXITWITHERR("mx_sync_mailbox");*/ } - /* not reached */ +#undef EXITWITHERR +#endif /* DEBUG */ }