X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fglobal.c;h=4f263e2dec2fb5688ba5a7df34cb69ddeed7e7ca;hb=HEAD;hp=cd6a43c1b081ce4a9a6f0470eeec267cdcc7aee6;hpb=9c6be56bf819c624f8e7b0a0ebbe77fe14cb3e0f;p=srvx.git diff --git a/src/global.c b/src/global.c index cd6a43c..4f263e2 100644 --- a/src/global.c +++ b/src/global.c @@ -1,11 +1,12 @@ /* global.c - Global notice service * Copyright 2000-2004 srvx Development Team * - * This program is free software; you can redistribute it and/or modify + * This file is part of srvx. + * + * srvx 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 of the License, or - * (at your option) any later version. Important limitations are - * listed in the COPYING file that accompanies this software. + * (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 @@ -13,7 +14,8 @@ * 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, email srvx-maintainers@srvx.net. + * along with srvx; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "conf.h" @@ -23,22 +25,21 @@ #include "saxdb.h" #include "timeq.h" -#define GLOBAL_CONF_NAME "services/global" +#define GLOBAL_CONF_NAME "services/global" -#define GLOBAL_DB "global.db" -#define GLOBAL_TEMP_DB "global.db.new" +#define GLOBAL_DB "global.db" +#define GLOBAL_TEMP_DB "global.db.new" /* Global options */ -#define KEY_DB_BACKUP_FREQ "db_backup_freq" -#define KEY_ANNOUNCEMENTS_DEFAULT "announcements_default" -#define KEY_NICK "nick" +#define KEY_DB_BACKUP_FREQ "db_backup_freq" +#define KEY_NICK "nick" /* Message data */ -#define KEY_FLAGS "flags" -#define KEY_POSTED "posted" -#define KEY_DURATION "duration" -#define KEY_FROM "from" -#define KEY_MESSAGE "message" +#define KEY_FLAGS "flags" +#define KEY_POSTED "posted" +#define KEY_DURATION "duration" +#define KEY_FROM "from" +#define KEY_MESSAGE "message" /* Clarification: Notices are immediate, they are sent to matching users _once_, then forgotten. Messages are stored in Global's database and @@ -63,35 +64,54 @@ static const struct message_entry msgtab[] = { #define GLOBAL_SYNTAX() svccmd_send_help(user, global, cmd) #define GLOBAL_FUNC(NAME) MODCMD_FUNC(NAME) +struct globalMessage +{ + unsigned long id; + long flags; + + unsigned long posted; + char posted_s[24]; + unsigned long duration; + + char *from; + char *message; + + struct globalMessage *prev; + struct globalMessage *next; +}; + struct userNode *global; static struct module *global_module; static struct service *global_service; static struct globalMessage *messageList; static long messageCount; -static time_t last_max_alert; +static unsigned long last_max_alert; static struct log_type *G_LOG; static struct { unsigned long db_backup_frequency; - unsigned int announcements_default : 1; } global_conf; -#define global_notice(target, format...) send_message(target , global , ## format) +#if defined(GCC_VARMACROS) +# define global_notice(target, ARGS...) send_message(target, global, ARGS) +#elif defined(C99_VARMACROS) +# define global_notice(target, ...) send_message(target, global, __VA_ARGS__) +#endif void message_expire(void *data); static struct globalMessage* -message_add(long flags, time_t posted, unsigned long duration, char *from, const char *msg) +message_add(long flags, unsigned long posted, unsigned long duration, char *from, const char *msg) { struct globalMessage *message; + time_t feh; message = malloc(sizeof(struct globalMessage)); - if(!message) { - return NULL; + return NULL; } message->id = messageCount++; @@ -101,11 +121,16 @@ message_add(long flags, time_t posted, unsigned long duration, char *from, const message->from = strdup(from); message->message = strdup(msg); + if ((flags & MESSAGE_OPTION_IMMEDIATE) == 0) { + feh = message->posted; + strftime(message->posted_s, sizeof(message->posted_s), + "%I:%M %p, %m/%d/%Y", localtime(&feh)); + } + if(messageList) { - messageList->prev = message; + messageList->prev = message; } - message->prev = NULL; message->next = messageList; @@ -113,7 +138,7 @@ message_add(long flags, time_t posted, unsigned long duration, char *from, const if(duration) { - timeq_add(now + duration, message_expire, message); + timeq_add(now + duration, message_expire, message); } return message; @@ -124,7 +149,7 @@ message_del(struct globalMessage *message) { if(message->duration) { - timeq_del(0, NULL, message, TIMEQ_IGNORE_FUNC | TIMEQ_IGNORE_WHEN); + timeq_del(0, NULL, message, TIMEQ_IGNORE_FUNC | TIMEQ_IGNORE_WHEN); } if(message->prev) message->prev->next = message->next; @@ -150,65 +175,68 @@ message_create(struct userNode *user, unsigned int argc, char *argv[]) { unsigned long duration = 0; char *text = NULL; + char *sender; long flags = 0; unsigned int i; + sender = user->handle_info->handle; + for(i = 0; i < argc; i++) { - if((i + 1) > argc) - { - global_notice(user, "MSG_MISSING_PARAMS", argv[argc]); - return NULL; - } - - if(!irccasecmp(argv[i], "text")) - { - i++; - text = unsplit_string(argv + i, argc - i, NULL); - break; - } else if (!irccasecmp(argv[i], "sourceless")) { - i++; - flags |= MESSAGE_OPTION_SOURCELESS; - } else if (!irccasecmp(argv[i], "target")) { - i++; - - if(!irccasecmp(argv[i], "all")) { - flags |= MESSAGE_RECIPIENT_ALL; - } else if(!irccasecmp(argv[i], "users")) { - flags |= MESSAGE_RECIPIENT_LUSERS; - } else if(!irccasecmp(argv[i], "helpers")) { - flags |= MESSAGE_RECIPIENT_HELPERS; - } else if(!irccasecmp(argv[i], "opers")) { - flags |= MESSAGE_RECIPIENT_OPERS; - } else if(!irccasecmp(argv[i], "staff") || !irccasecmp(argv[i], "privileged")) { - flags |= MESSAGE_RECIPIENT_STAFF; - } else if(!irccasecmp(argv[i], "channels")) { - flags |= MESSAGE_RECIPIENT_CHANNELS; - } else if(!irccasecmp(argv[i], "announcement") || !irccasecmp(argv[i], "announce")) { - flags |= MESSAGE_RECIPIENT_ANNOUNCE; - } else { - global_notice(user, "GMSG_INVALID_TARGET", argv[i]); - return NULL; - } - } else if (irccasecmp(argv[i], "duration") == 0) { - duration = ParseInterval(argv[++i]); - } else { - global_notice(user, "MSG_INVALID_CRITERIA", argv[i]); - return NULL; - } + if((i + 1) > argc) + { + global_notice(user, "MSG_MISSING_PARAMS", argv[argc]); + return NULL; + } + + if(!irccasecmp(argv[i], "text")) + { + i++; + text = unsplit_string(argv + i, argc - i, NULL); + break; + } else if (!irccasecmp(argv[i], "sourceless")) { + i++; + flags |= MESSAGE_OPTION_SOURCELESS; + } else if (!irccasecmp(argv[i], "target")) { + i++; + + if(!irccasecmp(argv[i], "all")) { + flags |= MESSAGE_RECIPIENT_ALL; + } else if(!irccasecmp(argv[i], "users")) { + flags |= MESSAGE_RECIPIENT_LUSERS; + } else if(!irccasecmp(argv[i], "helpers")) { + flags |= MESSAGE_RECIPIENT_HELPERS; + } else if(!irccasecmp(argv[i], "opers")) { + flags |= MESSAGE_RECIPIENT_OPERS; + } else if(!irccasecmp(argv[i], "staff") || !irccasecmp(argv[i], "privileged")) { + flags |= MESSAGE_RECIPIENT_STAFF; + } else if(!irccasecmp(argv[i], "channels")) { + flags |= MESSAGE_RECIPIENT_CHANNELS; + } else { + global_notice(user, "GMSG_INVALID_TARGET", argv[i]); + return NULL; + } + } else if (irccasecmp(argv[i], "duration") == 0) { + duration = ParseInterval(argv[++i]); + } else if (irccasecmp(argv[i], "from") == 0) { + sender = argv[++i]; + } else { + global_notice(user, "MSG_INVALID_CRITERIA", argv[i]); + return NULL; + } } if(!flags) { - flags = MESSAGE_RECIPIENT_LUSERS; + flags = MESSAGE_RECIPIENT_LUSERS; } if(!text) { - global_notice(user, "GMSG_MESSAGE_REQUIRED"); - return NULL; + global_notice(user, "GMSG_MESSAGE_REQUIRED"); + return NULL; } - return message_add(flags, now, duration, user->handle_info->handle, text); + return message_add(flags, now, duration, sender, text); } static const char * @@ -216,31 +244,27 @@ messageType(const struct globalMessage *message) { if((message->flags & MESSAGE_RECIPIENT_ALL) == MESSAGE_RECIPIENT_ALL) { - return "all"; + return "all"; } if((message->flags & MESSAGE_RECIPIENT_STAFF) == MESSAGE_RECIPIENT_STAFF) { - return "staff"; - } - else if(message->flags & MESSAGE_RECIPIENT_ANNOUNCE) - { - return "announcement"; + return "staff"; } else if(message->flags & MESSAGE_RECIPIENT_OPERS) { - return "opers"; + return "opers"; } else if(message->flags & MESSAGE_RECIPIENT_HELPERS) { - return "helpers"; + return "helpers"; } else if(message->flags & MESSAGE_RECIPIENT_LUSERS) { - return "users"; + return "users"; } else { - return "channels"; + return "channels"; } } @@ -249,19 +273,14 @@ notice_target(const char *target, struct globalMessage *message) { if(!(message->flags & MESSAGE_OPTION_SOURCELESS)) { - if(message->flags & MESSAGE_OPTION_IMMEDIATE) - { - send_target_message(0, target, global, "GMSG_NOTICE_SOURCE", messageType(message), message->from); - } - else - { - char posted[24]; - struct tm tm; - - localtime_r(&message->posted, &tm); - strftime(posted, sizeof(posted), "%I:%M %p, %m/%d/%Y", &tm); - send_target_message(0, target, global, "GMSG_MESSAGE_SOURCE", messageType(message), message->from, posted); - } + if(message->flags & MESSAGE_OPTION_IMMEDIATE) + { + send_target_message(0, target, global, "GMSG_NOTICE_SOURCE", messageType(message), message->from); + } + else + { + send_target_message(0, target, global, "GMSG_MESSAGE_SOURCE", messageType(message), message->from, message->posted_s); + } } send_target_message(4, target, global, "%s", message->message); @@ -273,7 +292,7 @@ notice_channel(const char *key, void *data, void *extra) struct chanNode *channel = data; /* It should be safe to assume channel is not NULL. */ if(channel->channel_info) - notice_target(key, extra); + notice_target(key, extra); return 0; } @@ -282,55 +301,40 @@ message_send(struct globalMessage *message) { struct userNode *user; unsigned long n; - dict_iterator_t it; if(message->flags & MESSAGE_RECIPIENT_CHANNELS) { - dict_foreach(channels, notice_channel, message); + dict_foreach(channels, notice_channel, message); } if(message->flags & MESSAGE_RECIPIENT_LUSERS) { - notice_target("$*", message); - return; - } - - if(message->flags & MESSAGE_RECIPIENT_ANNOUNCE) - { - char announce; - - for (it = dict_first(clients); it; it = iter_next(it)) { - user = iter_data(it); - if (user->uplink == self) continue; - announce = user->handle_info ? user->handle_info->announcements : '?'; - if (announce == 'n') continue; - if ((announce == '?') && !global_conf.announcements_default) continue; - notice_target(user->nick, message); - } + notice_target("$*", message); + return; } if(message->flags & MESSAGE_RECIPIENT_OPERS) { - for(n = 0; n < curr_opers.used; n++) - { - user = curr_opers.list[n]; - - if(user->uplink != self) - { - notice_target(user->nick, message); - } - } + for(n = 0; n < curr_opers.used; n++) + { + user = curr_opers.list[n]; + + if(user->uplink != self) + { + notice_target(user->nick, message); + } + } } if(message->flags & MESSAGE_RECIPIENT_HELPERS) { - for(n = 0; n < curr_helpers.used; n++) - { - user = curr_helpers.list[n]; + for(n = 0; n < curr_helpers.used; n++) + { + user = curr_helpers.list[n]; if (IsOper(user)) continue; - notice_target(user->nick, message); - } + notice_target(user->nick, message); + } } } @@ -340,11 +344,11 @@ global_message(long targets, char *text) struct globalMessage *message; if(!targets || !global) - return; + return; message = message_add(targets | MESSAGE_OPTION_SOURCELESS, now, 0, "", text); if(!message) - return; + return; message_send(message); message_del(message); @@ -354,38 +358,44 @@ static GLOBAL_FUNC(cmd_notice) { struct globalMessage *message = NULL; const char *recipient = NULL, *text; + char *sender; long target = 0; assert(argc >= 3); + sender = user->handle_info->handle; if(!irccasecmp(argv[1], "all")) { - target = MESSAGE_RECIPIENT_ALL; + target = MESSAGE_RECIPIENT_ALL; } else if(!irccasecmp(argv[1], "users")) { - target = MESSAGE_RECIPIENT_LUSERS; + target = MESSAGE_RECIPIENT_LUSERS; } else if(!irccasecmp(argv[1], "helpers")) { - target = MESSAGE_RECIPIENT_HELPERS; + target = MESSAGE_RECIPIENT_HELPERS; } else if(!irccasecmp(argv[1], "opers")) { - target = MESSAGE_RECIPIENT_OPERS; + target = MESSAGE_RECIPIENT_OPERS; } else if(!irccasecmp(argv[1], "staff") || !irccasecmp(argv[1], "privileged")) { - target |= MESSAGE_RECIPIENT_HELPERS | MESSAGE_RECIPIENT_OPERS; - } else if(!irccasecmp(argv[1], "announcement") || !irccasecmp(argv[1], "announce")) { - target |= MESSAGE_RECIPIENT_ANNOUNCE; + target |= MESSAGE_RECIPIENT_HELPERS | MESSAGE_RECIPIENT_OPERS; } else if(!irccasecmp(argv[1], "channels")) { - target = MESSAGE_RECIPIENT_CHANNELS; + target = MESSAGE_RECIPIENT_CHANNELS; } else { - global_notice(user, "GMSG_INVALID_TARGET", argv[1]); - return 0; + global_notice(user, "GMSG_INVALID_TARGET", argv[1]); + return 0; + } + if(!irccasecmp(argv[2], "from")) { + if (argc < 5) { + reply("MSG_MISSING_PARAMS", argv[0]); + GLOBAL_SYNTAX(); + return 0; + } + sender = argv[3]; + text = unsplit_string(argv + 4, argc - 4, NULL); + } else { + text = unsplit_string(argv + 2, argc - 2, NULL); } - text = unsplit_string(argv + 2, argc - 2, NULL); - message = message_add(target | MESSAGE_OPTION_IMMEDIATE, now, 0, user->handle_info->handle, text); - + message = message_add(target | MESSAGE_OPTION_IMMEDIATE, now, 0, sender, text); if(!message) - { - return 0; - } + return 0; recipient = messageType(message); - message_send(message); message_del(message); @@ -415,7 +425,7 @@ static GLOBAL_FUNC(cmd_list) if(!messageList) { - global_notice(user, "GMSG_NO_MESSAGES"); + global_notice(user, "GMSG_NO_MESSAGES"); return 1; } @@ -440,22 +450,18 @@ static GLOBAL_FUNC(cmd_list) table.contents[nn][0] = strdup(buffer); table.contents[nn][1] = messageType(message); if(message->duration) - { - intervalString(buffer, message->posted + message->duration - now); - } + intervalString(buffer, message->posted + message->duration - now, user->handle_info); else - { strcpy(buffer, "Never."); - } table.contents[nn][2] = strdup(buffer); table.contents[nn][3] = message->from; - length = strlen(message->message); - safestrncpy(buffer, message->message, sizeof(buffer)); - if(length > (sizeof(buffer) - 4)) - { - buffer[sizeof(buffer) - 1] = 0; - buffer[sizeof(buffer) - 2] = buffer[sizeof(buffer) - 3] = buffer[sizeof(buffer) - 4] = '.'; - } + length = strlen(message->message); + safestrncpy(buffer, message->message, sizeof(buffer)); + if(length > (sizeof(buffer) - 4)) + { + buffer[sizeof(buffer) - 1] = 0; + buffer[sizeof(buffer) - 2] = buffer[sizeof(buffer) - 3] = buffer[sizeof(buffer) - 4] = '.'; + } table.contents[nn][4] = strdup(buffer); } table_send(global, user->nick, 0, NULL, table); @@ -482,12 +488,12 @@ static GLOBAL_FUNC(cmd_remove) for(message = messageList; message; message = message->next) { - if(message->id == id) - { - message_del(message); - global_notice(user, "GMSG_MESSAGE_DELETED", argv[1]); - return 1; - } + if(message->id == id) + { + message_del(message); + global_notice(user, "GMSG_MESSAGE_DELETED", argv[1]); + return 1; + } } global_notice(user, "GMSG_ID_INVALID", argv[1]); @@ -502,15 +508,15 @@ send_messages(struct userNode *user, long mask, int obstreperize) while(message) { - if(message->flags & mask) - { + if(message->flags & mask) + { if (obstreperize && !count) send_target_message(0, user->nick, global, "GMSG_MOTD_HEADER"); - notice_target(user->nick, message); - count++; - } + notice_target(user->nick, message); + count++; + } - message = message->next; + message = message->next; } if (obstreperize && count) send_target_message(0, user->nick, global, "GMSG_MOTD_FOOTER"); @@ -523,25 +529,25 @@ static GLOBAL_FUNC(cmd_messages) unsigned int count; if(IsOper(user)) - mask |= MESSAGE_RECIPIENT_OPERS; + mask |= MESSAGE_RECIPIENT_OPERS; if(IsHelper(user)) - mask |= MESSAGE_RECIPIENT_HELPERS; + mask |= MESSAGE_RECIPIENT_HELPERS; count = send_messages(user, mask, 0); if(count) - global_notice(user, "GMSG_MESSAGE_COUNT", count); + global_notice(user, "GMSG_MESSAGE_COUNT", count); else - global_notice(user, "GMSG_NO_MESSAGES"); + global_notice(user, "GMSG_NO_MESSAGES"); return 1; } -static int +static void global_process_user(struct userNode *user) { if(IsLocal(user) || self->uplink->burst || user->uplink->burst) - return 0; + return; send_messages(user, MESSAGE_RECIPIENT_LUSERS, 1); /* only alert on new usercount if the record was broken in the last @@ -549,21 +555,19 @@ global_process_user(struct userNode *user) */ if((now - max_clients_time) <= 30 && (now - last_max_alert) > 30) { - char *message; - message = alloca(36); - sprintf(message, "New user count record: %d", max_clients); - global_message(MESSAGE_RECIPIENT_OPERS, message); - last_max_alert = now; + char *message; + message = alloca(36); + sprintf(message, "New user count record: %d", max_clients); + global_message(MESSAGE_RECIPIENT_OPERS, message); + last_max_alert = now; } - - return 0; } static void global_process_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) { if(IsHelper(user)) - send_messages(user, MESSAGE_RECIPIENT_HELPERS, 0); + send_messages(user, MESSAGE_RECIPIENT_HELPERS, 0); } static void @@ -581,14 +585,12 @@ global_conf_read(void) const char *str; if (!(conf_node = conf_get_data(GLOBAL_CONF_NAME, RECDB_OBJECT))) { - log_module(G_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", GLOBAL_CONF_NAME); - return; + log_module(G_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", GLOBAL_CONF_NAME); + return; } str = database_get_data(conf_node, KEY_DB_BACKUP_FREQ, RECDB_QSTRING); global_conf.db_backup_frequency = str ? ParseInterval(str) : 7200; - str = database_get_data(conf_node, KEY_ANNOUNCEMENTS_DEFAULT, RECDB_QSTRING); - global_conf.announcements_default = str ? enabled_string(str) : 1; str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING); if(global && str) @@ -599,7 +601,7 @@ static int global_saxdb_read(struct dict *db) { struct record_data *hir; - time_t posted; + unsigned long posted; long flags; unsigned long duration; char *str, *from, *message; @@ -608,11 +610,11 @@ global_saxdb_read(struct dict *db) for(it=dict_first(db); it; it=iter_next(it)) { hir = iter_data(it); - if(hir->type != RECDB_OBJECT) - { - log_module(G_LOG, LOG_WARNING, "Unexpected rectype %d for %s.", hir->type, iter_key(it)); + if(hir->type != RECDB_OBJECT) + { + log_module(G_LOG, LOG_WARNING, "Unexpected rectype %d for %s.", hir->type, iter_key(it)); continue; - } + } str = database_get_data(hir->d.object, KEY_FLAGS, RECDB_QSTRING); flags = str ? strtoul(str, NULL, 0) : 0; @@ -626,7 +628,7 @@ global_saxdb_read(struct dict *db) from = database_get_data(hir->d.object, KEY_FROM, RECDB_QSTRING); message = database_get_data(hir->d.object, KEY_MESSAGE, RECDB_QSTRING); - message_add(flags, posted, duration, from, message); + message_add(flags, posted, duration, from, message); } return 0; } @@ -676,8 +678,9 @@ init_global(const char *nick) if(nick) { - global = AddService(nick, "Global Services"); - global_service = service_register(global, 0); + const char *modes = conf_get_data("services/global/modes", RECDB_QSTRING); + global = AddLocalUser(nick, nick, NULL, "Global Services", modes); + global_service = service_register(global); } saxdb_register("Global", global_saxdb_read, global_saxdb_write); reg_exit_func(global_db_cleanup);