From 898026eba8e1d97d881808d7dfd3c79a58bda6cc Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Mon, 29 Mar 2004 21:10:10 +0000 Subject: [PATCH] automatic arch-version.h update; CTCP support; helpfile fixes; disk-out-of-space error detection and handling * Add a rule to automatically check arch version and update arch-version.h when needed * Implement CTCP response handling messages direct to services. * Fix grammar error in GIVEOWNERSHIP help entry, fix cross-reference markup in several ChanServ commands (should underline, not bold, the "See Also:" link), remove VERSION help entries from modules that no longer implement that command. * Check for errors (using setjmp/longjmp) when writing to a saxdb file, and log the failures. git-archimport-id: srvx@srvx.net--2004-srvx/srvx--devo--1.3--patch-36 --- src/Makefile.am | 20 +++++++---- src/chanserv.help | 24 ++++++------- src/global.help | 2 -- src/mod-helpserv.c | 67 +++++++++++++++++------------------ src/mod-memoserv.help | 3 -- src/modcmd.c | 81 +++++++++++++++++++++++++++++++++++++------ src/opserv.help | 2 -- src/proto-bahamut.c | 5 +++ src/proto-p10.c | 6 ++++ src/proto.h | 1 + src/saxdb.c | 37 ++++++++++---------- src/saxdb.h | 12 ++++++- src/tools.c | 9 ++--- 13 files changed, 172 insertions(+), 97 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c31f287..f605f86 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,13 +7,19 @@ noinst_DATA = chanserv.help global.help modcmd.help nickserv.help opserv.help sa EXTRA_DIST = $(noinst_DATA) BUILT_SOURCES = arch-version.h noinst_HEADERS = arch-version.h -arch-version.h: - @if [ -e $@ ] ; then OLD_REVISION=`cat $@` ; else OLD_REVISION="" ; fi ; \ - ARCH_REVISION=`tla logs -f | tail -n 1` ; \ - VERSION_CONTENTS="#define ARCH_VERSION \"$$ARCH_REVISION\"" ; \ - if [ "z" != "z$$ARCH_REVISION" -a "z$$OLD_REVISION" != "z$$VERSION_CONTENTS" ] ; then \ - echo "Putting new arch version into $@" ; \ - echo $$VERSION_CONTENTS > $@ ; \ + +.PHONY: checkversion +arch-version.h: checkversion +checkversion: + @tla logs -f >/dev/null || exit 0; \ + TMPFILE=`mktemp arch-version.h.XXXXXX` || exit 1 ; \ + echo "#define ARCH_VERSION \"`tla logs -f | tail -n 1`\"" >> $$TMPFILE ; \ + if diff -q arch-version.h $$TMPFILE >/dev/null 2>&1 ; then \ + rm $$TMPFILE ; \ + else \ + echo "Putting new arch version into arch-version.h" ; \ + rm -f arch-version.h ; \ + mv $$TMPFILE arch-version.h ; \ fi EXTRA_srvx_SOURCES = proto-bahamut.c proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c mod-helpserv.c mod-sockcheck.c diff --git a/src/chanserv.help b/src/chanserv.help index b8d59f9..db953ca 100644 --- a/src/chanserv.help +++ b/src/chanserv.help @@ -145,7 +145,7 @@ "If the note type already exists, it is modified with the new values you specify.", "$uSee Also:$u removenote"); "GIVEOWNERSHIP" ("/msg $C GIVEOWNERSHIP <#channel> ", - "Transfer ownership of the channel from you to another user on the channel's userlist. You are demoted to co-owner, and they are promoted to owner.", + "Transfer ownership of the channel from you to another user on the channel's userlist. You are demoted to co-owner, and he or she is promoted to owner.", "You may use *Account instead of Nick as the name argument; the * makes $C use the name of a account directly (useful if the user is not online).", "$uSee Also:$u clvl, access, users"); "CSUSPEND" ("/msg $C CSUSPEND <#channel> [!] ", @@ -155,7 +155,7 @@ "$uSee Also:$u unregister, cunsuspend, durations"); "CUNSUSPEND" ("/msg $C CUNSUSPEND <#channel>", "Restores a channel's $b$C$b registration.", - "$bSee Also:$b csuspend, unregister"); + "$uSee Also:$u csuspend, unregister"); "DELBAN" ("/msg $C DELBAN <#channel> ", "Deletes a ban from the channel ban list. This command works for both permanent and timed bans alike.", "$uSee Also:$u addban, addtimedban, bans"); @@ -211,16 +211,16 @@ "$uSee Also:$u staff"); "KICK" ("/msg $C KICK <#channel> [reason]", "Kicks the users matching the given nick or mask with the specified reason. If no reason is provided, a default will be used.", - "$bSee Also:$b kickban"); + "$uSee Also:$u kickban"); "KICKBAN" ("/msg $C KICKBAN <#channel> [reason]", "Kicks and bans with the specified reason any users with a matching nick or hostmask. If no reason is provided, a default one will be used.", - "$bSee Also:$b addban, kick"); + "$uSee Also:$u addban, kick"); "MDELCOOWNER" ("/msg $C MDELCOOWNER <#channel> ", "Deletes all coowners with accounts matching the given pattern from the channel user list.", - "$bSee Also:$b clist, delcoowner"); + "$uSee Also:$u clist, delcoowner"); "MDELMASTER" ("/msg $C MDELMASTER <#channel> ", "Deletes all masters with accounts matching the given pattern from the channel user list.", - "$bSee Also:$b mdelban, mdelcoowner, mdelop, mdelowner, mdelpeon"); + "$uSee Also:$u mdelban, mdelcoowner, mdelop, mdelowner, mdelpeon"); "MDELOP" ("/msg $C MDELOP <#channel> ", "Deletes all ops with accounts matching the given pattern from the channel user list."); "MDELOWNER" ("/msg $C MDELOWNER <#channel> ", @@ -412,23 +412,23 @@ "$uSee Also:$u durations"); "UNBAN" ("/msg $C UNBAN <#channel> ", "Unbans the specified nick or hostmask. If a nick is given, $b$C$b determines what hostmask(s) to unban.", - "$bSee Also:$b ban, kick, kickban"); + "$uSee Also:$u ban, kick, kickban"); "UNBANALL" ("/msg $C UNBANALL <#channel>", "Clears the specified channel's banlist. If the channel is omitted, then $bunbanall$b will be done in the channel where the command was given.", - "$bSee Also:$b ban, unban, unbanme"); + "$uSee Also:$u ban, unban, unbanme"); "UNBANME" ("/msg $C UNBANME <#channel>", "Unbans your hostmask from the specified channel.", - "$bSee Also:$b ban, unban"); + "$uSee Also:$u ban, unban"); "UNREGISTER" ("/msg $C UNREGISTER <#channel> []", "Unregisters a channel that is registered with $b$C$b. $bIMPORTANT$b: Once the channel is unregistered, the userlist $bcannot$b be recovered.", "If you are not network staff, you must add a confimation string to the end of your line to confirm the unregistration. If you leave it out, $C will show the proper confirmation string.", - "$bSee Also:$b register"); + "$uSee Also:$u register"); "UNSUSPEND" ("/msg $C UNSUSPEND <#channel> ", "This restores the target's access to the channel (after it has been suspended).", "$uSee Also:$u suspend, deluser"); "UNVISITED" ("/msg $C UNVISITED [duration] [limit]", "Displays up to a certain limit, all channels registered with $b$C$b that have not been visited within a certain duration. If a duration is not provided, a default will be used.", - "$bSee Also:$b expire, search, durations"); + "$uSee Also:$u expire, search, durations"); "UP" ("/msg $C UP <#channel>", "Grants you your normal channel privileges. If your access in the channel is less than the GiveVoice setting, this does nothing. Otherwise, if your access is less than the GiveOps setting, $b$C$b will give you voice. If your access is at least GiveOps, $b$C$b will give you ops."); "UPALL" ("/msg $C UPALL", @@ -448,8 +448,6 @@ "USERS" ("/msg $C USERS <#channel> [mask]", "Displays the userlist for the specified channel. If a mask is supplied, only users matching the mask will be shown.", "$uSee Also:$u clist, mlist, olist, plist, wlist"); -"VERSION" ("/msg $C VERSION", - "Sends you the srvx version and some additional version information that is specific to $b$C$b."); "VOICE" ("/msg $C VOICE <#channel> [nick]...", "Voices the specified nick in the specified channel. If the channel is omitted, then $bvoice$b will be done in the channel where the command was given.", "$uSee Also:$u devoice"); diff --git a/src/global.help b/src/global.help index 19396d9..1282439 100644 --- a/src/global.help +++ b/src/global.help @@ -33,5 +33,3 @@ "$bSTAFF$b: The message will be sent to helpers and opers.", "$bCHANNELS$b: The message will be sent to all channels.", "$bALL$b: A combination of USERS and CHANNELS."); -"VERSION" ("/msg $G VERSION", - "$bVERSION$b causes $b$G$b to to send you the srvx version and some additional version information that is specific to $b$G$b."); diff --git a/src/mod-helpserv.c b/src/mod-helpserv.c index 5bf57eb..177e11e 100644 --- a/src/mod-helpserv.c +++ b/src/mod-helpserv.c @@ -482,7 +482,6 @@ static struct { static time_t last_stats_update; static int shutting_down; static FILE *reqlog_f; -static struct saxdb_context *reqlog_ctx; static struct log_type *HS_LOG; #define CMD_NEED_BOT 0x001 @@ -692,33 +691,38 @@ static struct helpserv_user *GetHSUser(struct helpserv_bot *hs, struct handle_in static void helpserv_log_request(struct helpserv_request *req, const char *reason) { char key[27+NICKLEN]; char userhost[USERLEN+HOSTLEN+2]; + struct saxdb_context *ctx; + int res; - if (!reqlog_ctx || !req) + assert(req != NULL); + assert(reason != NULL); + if (!(ctx = saxdb_open_context(reqlog_f))) return; - if (!reason) - reason = ""; - sprintf(key, "%s-" FMT_TIME_T "-%lu", req->hs->helpserv->nick, req->opened, req->id); - saxdb_start_record(reqlog_ctx, key, 1); - if (req->helper) { - saxdb_write_string(reqlog_ctx, KEY_REQUEST_HELPER, req->helper->handle->handle); - saxdb_write_int(reqlog_ctx, KEY_REQUEST_ASSIGNED, req->assigned); - } - if (req->handle) { - saxdb_write_string(reqlog_ctx, KEY_REQUEST_HANDLE, req->handle->handle); - } - if (req->user) { - saxdb_write_string(reqlog_ctx, KEY_REQUEST_NICK, req->user->nick); - sprintf(userhost, "%s@%s", req->user->ident, req->user->hostname); - saxdb_write_string(reqlog_ctx, KEY_REQUEST_USERHOST, userhost); + if ((res = setjmp(ctx->jbuf)) != 0) { + log_module(HS_LOG, LOG_ERROR, "Unable to log helpserv request: %s.", strerror(res)); + } else { + saxdb_start_record(ctx, key, 1); + if (req->helper) { + saxdb_write_string(ctx, KEY_REQUEST_HELPER, req->helper->handle->handle); + saxdb_write_int(ctx, KEY_REQUEST_ASSIGNED, req->assigned); + } + if (req->handle) { + saxdb_write_string(ctx, KEY_REQUEST_HANDLE, req->handle->handle); + } + if (req->user) { + saxdb_write_string(ctx, KEY_REQUEST_NICK, req->user->nick); + sprintf(userhost, "%s@%s", req->user->ident, req->user->hostname); + saxdb_write_string(ctx, KEY_REQUEST_USERHOST, userhost); + } + saxdb_write_int(ctx, KEY_REQUEST_OPENED, req->opened); + saxdb_write_int(ctx, KEY_REQUEST_CLOSED, now); + saxdb_write_string(ctx, KEY_REQUEST_CLOSEREASON, reason); + saxdb_write_string_list(ctx, KEY_REQUEST_TEXT, req->text); + saxdb_end_record(ctx); + saxdb_close_context(ctx); + fflush(reqlog_f); } - saxdb_write_int(reqlog_ctx, KEY_REQUEST_OPENED, req->opened); - saxdb_write_int(reqlog_ctx, KEY_REQUEST_CLOSED, now); - saxdb_write_string(reqlog_ctx, KEY_REQUEST_CLOSEREASON, reason); - saxdb_write_string_list(reqlog_ctx, KEY_REQUEST_TEXT, req->text); - saxdb_end_record(reqlog_ctx); - - fflush(reqlog_f); } /* Searches for a request by number, nick, or account (num|nick|*account). @@ -3661,20 +3665,13 @@ static void helpserv_conf_read(void) { str = database_get_data(conf_node, "user_escape", RECDB_QSTRING); helpserv_conf.user_escape = str ? str[0] : '@'; - if (reqlog_ctx) { - saxdb_close_context(reqlog_ctx); - reqlog_ctx = NULL; - } if (reqlog_f) { fclose(reqlog_f); reqlog_f = NULL; } - if (helpserv_conf.reqlogfile) { - if (!(reqlog_f = fopen(helpserv_conf.reqlogfile, "a"))) { - log_module(HS_LOG, LOG_ERROR, "Unable to open request logfile (%s): %s", helpserv_conf.reqlogfile, strerror(errno)); - } else { - reqlog_ctx = saxdb_open_context(reqlog_f); - } + if (helpserv_conf.reqlogfile + && !(reqlog_f = fopen(helpserv_conf.reqlogfile, "a"))) { + log_module(HS_LOG, LOG_ERROR, "Unable to open request logfile (%s): %s", helpserv_conf.reqlogfile, strerror(errno)); } } @@ -4461,8 +4458,6 @@ static void helpserv_db_cleanup(void) { dict_delete(helpserv_reqs_byhand_dict); dict_delete(helpserv_users_byhand_dict); - if (reqlog_ctx) - saxdb_close_context(reqlog_ctx); if (reqlog_f) fclose(reqlog_f); } diff --git a/src/mod-memoserv.help b/src/mod-memoserv.help index 88f30dc..5ce2e8c 100644 --- a/src/mod-memoserv.help +++ b/src/mod-memoserv.help @@ -23,9 +23,6 @@ "/msg $S SET notify <1 or 0>", "Decides wether $S should notify you of the messages in your inbox, on authentication with $N AND when someone sends you a new message."); -"VERSION" ("/msg $S VERSION", - "Sends you the srvx version and some additional version information that is specific to $b$S$b."); - "EXPIRY" ("/msg $S EXPIRY ", "Sends you the current usage of expiring old messages."); diff --git a/src/modcmd.c b/src/modcmd.c index 218c7c0..557373c 100644 --- a/src/modcmd.c +++ b/src/modcmd.c @@ -36,7 +36,6 @@ static struct pending_template *pending_templates; static struct module *modcmd_module; static struct modcmd *bind_command, *help_command, *version_command; static const struct message_entry msgtab[] = { - { "MCMSG_VERSION", "$b"PACKAGE_STRING"$b ("CODENAME"), Built: " __DATE__ ", " __TIME__"." }, { "MCMSG_BARE_FLAG", "Flag %.*s must be preceded by a + or -." }, { "MCMSG_UNKNOWN_FLAG", "Unknown module flag %.*s." }, { "MCMSG_BAD_OPSERV_LEVEL", "Invalid $O access level %s." }, @@ -120,6 +119,7 @@ static const struct message_entry msgtab[] = { { "MCMSG_SERVICE_REMOVED", "Service $b%s$b has been deleted." }, { "MCMSG_FILE_NOT_OPENED", "Unable to open file $b%s$b for writing." }, { "MCMSG_MESSAGES_DUMPED", "Messages written to $b%s$b." }, + { "MCMSG_MESSAGE_DUMP_FAILED", "Message dump failed: %s." }, { "MCMSG_COMMAND_FLAGS", "Command flags are %s (inferred: %s)." }, { "MCMSG_COMMAND_ACCOUNT_FLAGS", "Requires account flags +%s, prohibits account flags +%s." }, { "MCMSG_COMMAND_ACCESS_LEVEL", "Requires channel access %d and $O access %d." }, @@ -821,11 +821,63 @@ svccmd_invoke(struct userNode *user, struct service *service, struct chanNode *c void modcmd_privmsg(struct userNode *user, struct userNode *bot, char *text, int server_qualified) { struct service *service; + if (!(service = dict_find(services, bot->nick, NULL))) { log_module(MAIN_LOG, LOG_ERROR, "modcmd_privmsg got privmsg for unhandled service %s, unregistering.", bot->nick); reg_privmsg_func(bot, NULL); return; } + + if (text[0] == '\x01') { + char *term, response[MAXLEN]; + + text++; /* Skip leading ^A. */ + /* Chop off final ^A. */ + term = strchr(text, '\x01'); + if (!term) + return; + *term = '\0'; + /* Parse out leading text. */ + term = strchr(text, ' '); + if (term) { + *term++ = '\0'; + if (!*term) + term = NULL; + } + /* No dict lookup since these are so few. */ + if (!irccasecmp(text, "CLIENTINFO")) { + /* Use \001 instead of \x01 because apparently \x01C is + * interpreted as ASCII FS (\034, decimal 28, hex 1C). + */ + irc_notice_user(bot, user, "\001CLIENTINFO CLIENTINFO PING TIME USERINFO VERSION\x01"); + } else if (!irccasecmp(text, "PING")) { + if (term) { + snprintf(response, sizeof(response), "\x01PONG %s\x01", term); + irc_notice_user(bot, user, response); + } else { + irc_notice_user(bot,user, "\x01PONG\x01"); + } + } else if (!irccasecmp(text, "TIME")) { + struct tm tm; + localtime_r(&now, &tm); + strftime(response, sizeof(response), "\x01TIME %a %b %d %H:%M:%S %Y\x01", &tm); + irc_notice_user(bot, user, response); + } else if (!irccasecmp(text, "USERINFO")) { + snprintf(response, sizeof(response), "\x01USERINFO %s\x01", bot->info); + irc_notice_user(bot, user, response); + } else if (!irccasecmp(text, "VERSION")) { + /* This function provides copyright management information + * to end users of srvx. You should not alter, disable or + * remove this command or its accessibility to normal IRC + * users, except to add copyright information pertaining + * to changes you make to srvx. + */ + snprintf(response, sizeof(response), "\x01VERSION %s (%s) %s\x01", PACKAGE_STRING, CODENAME, ARCH_VERSION); + irc_notice_user(bot, user, response); + } + return; + } + if (service->msg_hook && service->msg_hook(user, bot, text, server_qualified)) return; svccmd_invoke(user, service, NULL, text, server_qualified); @@ -1768,6 +1820,7 @@ static MODCMD_FUNC(cmd_dump_messages) { struct saxdb_context *ctx; dict_iterator_t it; FILE *pf; + int res; if (!(pf = fopen(fname, "w"))) { reply("MCMSG_FILE_NOT_OPENED", fname); @@ -1777,21 +1830,29 @@ static MODCMD_FUNC(cmd_dump_messages) { reply("MSG_INTERNAL_FAILURE"); return 0; } - for (it = dict_first(lang_C->messages); it; it = iter_next(it)) - saxdb_write_string(ctx, iter_key(it), iter_data(it)); - saxdb_close_context(ctx); - fclose(pf); - reply("MCMSG_MESSAGES_DUMPED", fname); - return 1; + if ((res = setjmp(ctx->jbuf)) != 0) { + ctx->complex.used = 0; /* to avoid false assert()s in close */ + saxdb_close_context(ctx); + fclose(pf); + reply("MCMSG_MESSAGE_DUMP_FAILED", strerror(res)); + return 0; + } else { + for (it = dict_first(lang_C->messages); it; it = iter_next(it)) + saxdb_write_string(ctx, iter_key(it), iter_data(it)); + saxdb_close_context(ctx); + fclose(pf); + reply("MCMSG_MESSAGES_DUMPED", fname); + return 1; + } } static MODCMD_FUNC(cmd_version) { /* This function provides copyright management information to end * users of srvx. You should not alter, disable or remove this - * command or its accessibility to normal IRC users. + * command or its accessibility to normal IRC users, except to add + * copyright information pertaining to changes you make to srvx. */ - reply("MCMSG_VERSION"); - send_message_type(4, user, cmd->parent->bot, "Copyright 2000-2004 srvx Development Team.\nThe srvx Development Team includes Paul Chang, Adrian Dewhurst, Miles Peterson, Michael Poole and others.\nThe srvx Development Team can be reached at http://sf.net/projects/srvx/ or in #srvx on irc.gamesurge.net."); + send_message_type(4, user, cmd->parent->bot, "$b"PACKAGE_STRING"$b ("CODENAME"), Built: "__DATE__", "__TIME__".\nCopyright 2000-2004 srvx Development Team.\nThe srvx Development Team includes Paul Chang, Adrian Dewhurst, Miles Peterson, Michael Poole and others.\nThe srvx Development Team can be reached at http://sf.net/projects/srvx/ or in #srvx on irc.gamesurge.net."); if ((argc > 1) && !irccasecmp(argv[1], "arch")) send_message_type(4, user, cmd->parent->bot, "%s", ARCH_VERSION); return 1; diff --git a/src/opserv.help b/src/opserv.help index f5980e7..8998f74 100644 --- a/src/opserv.help +++ b/src/opserv.help @@ -413,8 +413,6 @@ "$bWARN$b: The list of channels with activity warnings.", "$bMODULES$b: Shows loaded modules that implement commands.", "$bSERVICES$b: Shows active service bots."); -"VERSION" ("/msg $O VERSION ", - "Sends you the srvx version and all version information for $b$C$b, $b$O$b, $b$N$b, and $b$G$b."); "INDEX" "${index}"; "SEX" ("$bSEX$b", diff --git a/src/proto-bahamut.c b/src/proto-bahamut.c index e0e9dec..401fadc 100644 --- a/src/proto-bahamut.c +++ b/src/proto-bahamut.c @@ -369,6 +369,11 @@ irc_notice(struct userNode *from, const char *to, const char *message) { putsock(":%s NOTICE %s :%s", from->nick, to, message); } +void +irc_notice_user(struct userNode *from, struct userNode *to, const char *message) { + putsock(":%s NOTICE %s :%s", from->nick, to->nick, message); +} + void irc_wallchops(UNUSED_ARG(struct userNode *from), UNUSED_ARG(const char *to), UNUSED_ARG(const char *message)) { } diff --git a/src/proto-p10.c b/src/proto-p10.c index 5a5e5a9..14430fd 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -474,6 +474,12 @@ irc_notice(struct userNode *from, const char *to, const char *message) putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message); } +void +irc_notice_user(struct userNode *from, struct userNode *to, const char *message) +{ + putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message); +} + void irc_privmsg(struct userNode *from, const char *to, const char *message) { diff --git a/src/proto.h b/src/proto.h index 09db7c3..3ed37d5 100644 --- a/src/proto.h +++ b/src/proto.h @@ -123,6 +123,7 @@ void irc_squit(struct server *srv, const char *message, const char *service_mess /* messages */ void irc_privmsg(struct userNode *from, const char *to, const char *message); void irc_notice(struct userNode *from, const char *to, const char *message); +void irc_notice_user(struct userNode *from, struct userNode *to, const char *message); void irc_wallchops(struct userNode *from, const char *to, const char *message); /* channel maintenance */ diff --git a/src/saxdb.c b/src/saxdb.c index 61c7e69..2ddd158 100644 --- a/src/saxdb.c +++ b/src/saxdb.c @@ -24,7 +24,6 @@ #include "saxdb.h" #include "timeq.h" -DECLARE_LIST(int_list, int); DEFINE_LIST(int_list, int); struct saxdb { @@ -39,15 +38,6 @@ struct saxdb { struct saxdb *prev; }; -struct saxdb_context { - FILE *output; - unsigned int indent; - struct int_list complex; - jmp_buf jbuf; - /* XXX: If jbuf is ever used, places that use saxdb_open_context() and - * saxdb_close_context() must be modified to fill it in */ -}; - #define COMPLEX(CTX) ((CTX)->complex.used ? ((CTX)->complex.list[(CTX)->complex.used-1]) : 1) static struct saxdb *last_db; @@ -65,7 +55,8 @@ saxdb_read_db(struct saxdb *db) { assert(db); assert(db->filename); data = parse_database(db->filename); - if (!data) return; + if (!data) + return; if (db->writer == saxdb_mondo_writer) { mondo_db = data; } else { @@ -145,7 +136,7 @@ saxdb_write_db(struct saxdb *db) { start = time(NULL); if ((res = setjmp(ctx.jbuf)) || (res2 = db->writer(&ctx))) { if (res) { - log_module(MAIN_LOG, LOG_ERROR, "Exception %d caught while writing to %s", res, tmp_fname); + log_module(MAIN_LOG, LOG_ERROR, "Error writing to %s: %s", tmp_fname, strerror(res)); } else { log_module(MAIN_LOG, LOG_ERROR, "Internal error %d while writing to %s", res2, tmp_fname); } @@ -188,18 +179,25 @@ saxdb_write_all(void) { for (it = dict_first(saxdbs); it; it = iter_next(it)) { db = iter_data(it); - if (!db->mondo_section) saxdb_write_db(db); + if (!db->mondo_section) + saxdb_write_db(db); } } -#define saxdb_put_char(DEST, CH) fputc(CH, (DEST)->output) -#define saxdb_put_string(DEST, CH) fputs(CH, (DEST)->output) +#define saxdb_put_char(DEST, CH) do { \ + if (fputc(CH, (DEST)->output) == EOF) \ + longjmp((DEST)->jbuf, errno); \ + } while (0) +#define saxdb_put_string(DEST, CH) do { \ + if (fputs(CH, (DEST)->output) == EOF) \ + longjmp((DEST)->jbuf, errno); \ + } while (0) static inline void saxdb_put_nchars(struct saxdb_context *dest, const char *name, int len) { - while (len--) { - fputc(*name++, dest->output); - } + while (len--) + if (fputc(*name++, dest->output) == EOF) + longjmp(dest->jbuf, errno); } static void @@ -209,7 +207,8 @@ saxdb_put_qstring(struct saxdb_context *dest, const char *str) { assert(str); saxdb_put_char(dest, '"'); while ((esc = strpbrk(str, "\\\a\b\t\n\v\f\r\""))) { - if (esc != str) saxdb_put_nchars(dest, str, esc-str); + if (esc != str) + saxdb_put_nchars(dest, str, esc-str); saxdb_put_char(dest, '\\'); switch (*esc) { case '\a': saxdb_put_char(dest, 'a'); break; diff --git a/src/saxdb.h b/src/saxdb.h index 9c57863..bc063c0 100644 --- a/src/saxdb.h +++ b/src/saxdb.h @@ -23,8 +23,18 @@ #include "recdb.h" +DECLARE_LIST(int_list, int); + struct saxdb; -struct saxdb_context; +/* This definition should ONLY be used so callers of + * saxdb_open_context() can initialize jbuf properly. */ +struct saxdb_context { + FILE *output; + unsigned int indent; + struct int_list complex; + jmp_buf jbuf; +}; + #define SAXDB_READER(NAME) int NAME(struct dict *db) typedef SAXDB_READER(saxdb_reader_func_t); diff --git a/src/tools.c b/src/tools.c index 4b85261..c2fc94e 100644 --- a/src/tools.c +++ b/src/tools.c @@ -115,7 +115,8 @@ split_line(char *line, int irc_colon, int argv_size, char *argv[]) int argc = 0; int n; while (*line && (argc < argv_size)) { - while (*line == ' ') *line++ = 0; + while (*line == ' ') + *line++ = 0; if (*line == ':' && irc_colon && argc > 0) { /* the rest is a single parameter */ argv[argc++] = line + 1; @@ -126,14 +127,14 @@ split_line(char *line, int irc_colon, int argv_size, char *argv[]) argv[argc++] = line; if (argc >= argv_size) break; - while (*line != ' ' && *line) line++; + while (*line != ' ' && *line) + line++; } #ifdef NDEBUG n = 0; #else - for (n=argc; n