1 /* global.c - Global notice service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
29 #define GLOBAL_CONF_NAME "services/global"
31 #define GLOBAL_DB "global.db"
32 #define GLOBAL_TEMP_DB "global.db.new"
35 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
36 #define KEY_ANNOUNCEMENTS_DEFAULT "announcements_default"
37 #define KEY_NICK "nick"
40 #define KEY_FLAGS "flags"
41 #define KEY_POSTED "posted"
42 #define KEY_DURATION "duration"
43 #define KEY_FROM "from"
44 #define KEY_MESSAGE "message"
46 /* Clarification: Notices are immediate, they are sent to matching users
47 _once_, then forgotten. Messages are stored in Global's database and
48 continually sent to users as they match the target specification until
50 static const struct message_entry msgtab
[] = {
51 { "GMSG_INVALID_TARGET", "$b%s$b is an invalid message target." },
52 { "GMSG_MESSAGE_REQUIRED", "You $bmust$b provide a message to send." },
53 { "GMSG_MESSAGE_SENT", "Message to $b%s$b sent." },
54 { "GMSG_MESSAGE_ADDED", "Message to $b%s$b with ID %ld added." },
55 { "GMSG_MESSAGE_DELETED", "Message $b%s$b deleted." },
56 { "GMSG_ID_INVALID", "$b%s$b is an invalid message ID." },
57 { "GMSG_MESSAGE_COUNT", "$b%d$b messages found." },
58 { "GMSG_NO_MESSAGES", "There are no messages for you." },
59 { "GMSG_NOTICE_SOURCE", "Notice to [$b%s$b] from %s:" },
60 { "GMSG_MESSAGE_SOURCE", "Notice to [$b%s$b] from %s, posted %s:" },
61 //{ "GMSG_MOTD_HEADER", "$b------------- MESSAGE(S) OF THE DAY --------------$b" },
62 { "GMSG_MOTD_HEADER", "$bNetwork Announcements$b" },
63 { "GMSG_MOTD_BAR", "---------------------------------------" },
64 { "GMSG_MOTD_FOOTER", "--------------- Thank You--------------" },
66 /* These definitions are for other files that make use of global
67 * notices. Make sure you grep for them if you ever add args
71 { "CSMSG_REGISTERED_TO", "%s registered to %s by %s." },
72 { "CSMSG_CHANNEL_MOVED", "%s moved to %s by %s." },
73 { "CSMSG_SUSPENSION_MODIFIED", "%s suspension modified by %s." },
74 { "CSMSG_SUSPENDED_BY", "%s suspended by %s." },
75 { "CSMSG_UNSUSPENDED_BY", "%s unsuspended by %s." },
76 { "CSMSG_OWNERSHIP_TRANSFERRED", "%s ownership transferred to %s by %s." },
79 { "HSMSG_BOT_RENAMED", "HelpServ bot %s (in %s) renamed to %s by %s." },
80 { "HSMSG_BOT_MOVED", "HelpServ %s (%s) moved to %s by %s." },
81 { "HSMSG_BOT_REGISTERED", "HelpServ %s (%s) registered to %s by %s." },
82 { "HSMSG_BOT_EXPIRED", "HelpServ %s (%s) expired at request of %s." },
83 { "HSMSG_BOT_UNREGISTERED", "HelpServ %s (%s) unregistered by %s." },
84 { "HSMSG_SUSPENDED_BY", "%s suspended by %s. (HelpServ)" },
85 { "HSMSG_UNSUSPENDED_BY", "%s unsuspended by %s. (HelpServ)" },
88 { "NSMSG_ACCOUNT_RENAMED", "%s renamed account %s to %s." },
89 { "NSMSG_ACCOUNT_MERGED", "%s (%s) merged account %s into %s." },
92 { "DEFCON_NETWORK_CHANGED", "Network DefCon level has changed to level %d" },
93 { "DEFCON_OPER_LEVEL_CHANGE", "%s is changing the DefCon level to %d" },
94 { "DEFCON_TIMEOUT_LEVEL_CHANGE", "The DefCon has changed back to level %d (timeout)" },
95 { "OSMSG_CHANNEL_ACTIVITY_WARN", "Channel activity warning for channel %s: %s" },
98 { "SSMSG_CHANNEL_MERGED", "$X (channel %s) merged into %s by %s." },
99 { "SSMSG_CHANNEL_MOVED", "$X (channel %s) moved into %s by %s." },
100 { "SSMSG_UNREG_MANUAL", "$X (channel %s) %s by %s." },
101 { "SSMSG_REG_EXPIRED", "$X (channel %s) registration expired." },
102 { "SSMSG_LOST_ALL_USERS", "$X (channel %s) lost all users." },
103 { "SSMSG_REGISTERED_BY", "$X (channel %s) registered by %s." },
104 { "SSMSG_UNREGISTERED_BY", "$X (channel %s) unregistered by %s." },
109 #define GLOBAL_SYNTAX() svccmd_send_help_brief(user, global, cmd)
110 #define GLOBAL_FUNC(NAME) MODCMD_FUNC(NAME)
119 unsigned long duration
;
124 struct globalMessage
*prev
;
125 struct globalMessage
*next
;
128 struct userNode
*global
;
130 static struct module *global_module
;
131 static struct service
*global_service
;
132 static struct globalMessage
*messageList
;
133 extern struct string_list
*autojoin_channels
;
134 static long messageCount
;
135 static time_t last_max_alert
;
136 static struct log_type
*G_LOG
;
140 unsigned long db_backup_frequency
;
141 unsigned int announcements_default
: 1;
144 #if defined(GCC_VARMACROS)
145 # define global_notice(target, ARGS...) send_message(target, global, ARGS)
146 #elif defined(C99_VARMACROS)
147 # define global_notice(target, ...) send_message(target, global, __VA_ARGS__)
150 void message_expire(void *data
);
152 static struct globalMessage
*
153 message_add(long flags
, time_t posted
, unsigned long duration
, char *from
, const char *msg
)
155 struct globalMessage
*message
;
158 message
= malloc(sizeof(struct globalMessage
));
164 message
->id
= messageCount
++;
165 message
->flags
= flags
;
166 message
->posted
= posted
;
167 message
->duration
= duration
;
168 message
->from
= strdup(from
);
169 message
->message
= strdup(msg
);
171 if ((flags
& MESSAGE_OPTION_IMMEDIATE
) == 0) {
172 localtime_r(&message
->posted
, &tm
);
173 strftime(message
->posted_s
, sizeof(message
->posted_s
),
174 "%I:%M %p, %m/%d/%Y", &tm
);
179 messageList
->prev
= message
;
181 message
->prev
= NULL
;
182 message
->next
= messageList
;
184 messageList
= message
;
188 timeq_add(now
+ duration
, message_expire
, message
);
195 message_del(struct globalMessage
*message
)
197 if(message
->duration
)
199 timeq_del(0, NULL
, message
, TIMEQ_IGNORE_FUNC
| TIMEQ_IGNORE_WHEN
);
202 if(message
->prev
) message
->prev
->next
= message
->next
;
203 else messageList
= message
->next
;
205 if(message
->next
) message
->next
->prev
= message
->prev
;
208 free(message
->message
);
212 void message_expire(void *data
)
214 struct globalMessage
*message
= data
;
216 message
->duration
= 0;
217 message_del(message
);
220 static struct globalMessage
*
221 message_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
223 unsigned long duration
= 0;
229 sender
= user
->handle_info
->handle
;
231 for(i
= 0; i
< argc
; i
++)
235 global_notice(user
, "MSG_MISSING_PARAMS", argv
[argc
]);
239 if(!irccasecmp(argv
[i
], "text"))
242 text
= unsplit_string(argv
+ i
, argc
- i
, NULL
);
244 } else if (!irccasecmp(argv
[i
], "sourceless")) {
246 flags
|= MESSAGE_OPTION_SOURCELESS
;
247 } else if (!irccasecmp(argv
[i
], "target")) {
250 if(!irccasecmp(argv
[i
], "all")) {
251 flags
|= MESSAGE_RECIPIENT_ALL
;
252 } else if(!irccasecmp(argv
[i
], "authed")) {
253 flags
|= MESSAGE_RECIPIENT_AUTHED
;
254 } else if(!irccasecmp(argv
[i
], "users")) {
255 flags
|= MESSAGE_RECIPIENT_LUSERS
;
256 } else if(!irccasecmp(argv
[i
], "helpers")) {
257 flags
|= MESSAGE_RECIPIENT_HELPERS
;
258 } else if(!irccasecmp(argv
[i
], "opers")) {
259 flags
|= MESSAGE_RECIPIENT_OPERS
;
260 } else if(!irccasecmp(argv
[i
], "staff") || !irccasecmp(argv
[i
], "privileged")) {
261 flags
|= MESSAGE_RECIPIENT_STAFF
;
262 } else if(!irccasecmp(argv
[i
], "channels")) {
263 flags
|= MESSAGE_RECIPIENT_CHANNELS
;
264 } else if(!irccasecmp(argv
[i
], "rchannels")) {
265 flags
|= MESSAGE_RECIPIENT_RCHANNELS
;
266 } else if(!irccasecmp(argv
[i
], "announcement") || !irccasecmp(argv
[i
], "announce")) {
267 flags
|= MESSAGE_RECIPIENT_ANNOUNCE
;
269 global_notice(user
, "GMSG_INVALID_TARGET", argv
[i
]);
272 } else if (irccasecmp(argv
[i
], "duration") == 0) {
273 duration
= ParseInterval(argv
[++i
]);
274 } else if (irccasecmp(argv
[i
], "from") == 0) {
277 global_notice(user
, "MSG_INVALID_CRITERIA", argv
[i
]);
284 flags
= MESSAGE_RECIPIENT_LUSERS
;
288 global_notice(user
, "GMSG_MESSAGE_REQUIRED");
292 return message_add(flags
, now
, duration
, sender
, text
);
296 messageType(const struct globalMessage
*message
)
298 if((message
->flags
& MESSAGE_RECIPIENT_ALL
) == MESSAGE_RECIPIENT_ALL
)
302 if((message
->flags
& MESSAGE_RECIPIENT_STAFF
) == MESSAGE_RECIPIENT_STAFF
)
306 else if(message
->flags
& MESSAGE_RECIPIENT_ANNOUNCE
)
308 return "announcement";
310 else if(message
->flags
& MESSAGE_RECIPIENT_OPERS
)
314 else if(message
->flags
& MESSAGE_RECIPIENT_HELPERS
)
318 else if(message
->flags
& MESSAGE_RECIPIENT_LUSERS
)
322 else if(message
->flags
& MESSAGE_RECIPIENT_AUTHED
)
326 else if(message
->flags
& MESSAGE_RECIPIENT_RCHANNELS
)
337 notice_target(const char *target
, struct globalMessage
*message
)
339 if(!(message
->flags
& MESSAGE_OPTION_SOURCELESS
))
341 if(message
->flags
& MESSAGE_OPTION_IMMEDIATE
)
343 send_target_message(0, target
, global
, "GMSG_NOTICE_SOURCE", messageType(message
), message
->from
);
347 send_target_message(0, target
, global
, "GMSG_MESSAGE_SOURCE", messageType(message
), message
->from
, message
->posted_s
);
351 send_target_message(4, target
, global
, "%s", message
->message
);
355 message_send(struct globalMessage
*message
)
357 struct userNode
*user
;
361 if(message
->flags
& MESSAGE_RECIPIENT_CHANNELS
)
365 for (it
= dict_first(channels
); it
; it
= iter_next(it
)) {
366 struct chanNode
*chan
= iter_data(it
);
368 notice_target(chan
->name
, message
);
372 if(message
->flags
& MESSAGE_RECIPIENT_RCHANNELS
)
376 for (it
= dict_first(channels
); it
; it
= iter_next(it
)) {
377 struct chanNode
*chan
= iter_data(it
);
379 if (chan
->channel_info
)
380 notice_target(chan
->name
, message
);
384 if(message
->flags
& MESSAGE_RECIPIENT_LUSERS
)
386 notice_target("$*", message
);
390 if(message
->flags
& MESSAGE_RECIPIENT_ANNOUNCE
)
394 for (it
= dict_first(clients
); it
; it
= iter_next(it
)) {
395 user
= iter_data(it
);
396 if (user
->uplink
== self
) continue;
397 announce
= user
->handle_info
? user
->handle_info
->announcements
: '?';
398 if (announce
== 'n') continue;
399 if ((announce
== '?') && !global_conf
.announcements_default
) continue;
400 notice_target(user
->nick
, message
);
404 if(message
->flags
& MESSAGE_RECIPIENT_OPERS
)
406 for(n
= 0; n
< curr_opers
.used
; n
++)
408 user
= curr_opers
.list
[n
];
410 if(user
->uplink
!= self
)
412 notice_target(user
->nick
, message
);
417 if(message
->flags
& MESSAGE_RECIPIENT_HELPERS
)
419 for(n
= 0; n
< curr_helpers
.used
; n
++)
421 user
= curr_helpers
.list
[n
];
424 notice_target(user
->nick
, message
);
428 if(message
->flags
& MESSAGE_RECIPIENT_AUTHED
)
431 for (it
= dict_first(clients
); it
; it
= iter_next(it
)) {
432 struct userNode
*luser
= iter_data(it
);
433 if (luser
->handle_info
)
434 notice_target(luser
->nick
, message
);
440 global_message_args(long targets
, const char *language_entry
, ...)
442 struct globalMessage
*message
= NULL
;
445 char response
[MAXLEN
];
448 if(!targets
|| !global
)
451 fmt
= strdup(language_entry
);
453 /* Notice users/opers/helpers */
454 for (it
= dict_first(clients
); it
; it
= iter_next(it
)) {
455 struct userNode
*luser
= iter_data(it
);
457 language_entry
= user_find_message(luser
, fmt
);
459 va_start(arg_list
, language_entry
);
460 vsnprintf(response
, MAXLEN
-2, language_entry
, arg_list
);
461 response
[MAXLEN
-1] = 0;
464 message_del(message
);
466 message
= message_add(targets
| MESSAGE_OPTION_SOURCELESS
, now
, 0, "", response
);
471 if(message
->flags
& MESSAGE_RECIPIENT_OPERS
&& IsOper(luser
)) {
472 if(luser
->uplink
!= self
)
473 notice_target(luser
->nick
, message
);
475 if ((message
->flags
& MESSAGE_RECIPIENT_LUSERS
) || (message
->flags
& MESSAGE_RECIPIENT_HELPERS
) ||
476 (message
->flags
& MESSAGE_RECIPIENT_AUTHED
))
481 if (message
->flags
& MESSAGE_RECIPIENT_HELPERS
&& IsHelper(luser
)) {
482 notice_target(luser
->nick
, message
);
484 if ((message
->flags
& MESSAGE_RECIPIENT_LUSERS
) || (message
->flags
& MESSAGE_RECIPIENT_AUTHED
))
489 if ((message
->flags
& MESSAGE_RECIPIENT_AUTHED
) && luser
->handle_info
) {
490 notice_target(luser
->nick
, message
);
492 if (message
->flags
& MESSAGE_RECIPIENT_LUSERS
)
497 if (message
->flags
& MESSAGE_RECIPIENT_LUSERS
) {
498 notice_target(luser
->nick
, message
);
503 message_del(message
);
507 global_message(long targets
, char *text
)
509 struct globalMessage
*message
;
511 if(!targets
|| !global
)
514 message
= message_add(targets
| MESSAGE_OPTION_SOURCELESS
, now
, 0, "", text
);
518 message_send(message
);
519 message_del(message
);
522 static GLOBAL_FUNC(cmd_notice
)
524 struct globalMessage
*message
= NULL
;
525 const char *recipient
= NULL
, *text
;
530 sender
= user
->handle_info
->handle
;
531 if(!irccasecmp(argv
[1], "all")) {
532 target
= MESSAGE_RECIPIENT_ALL
;
533 } else if(!irccasecmp(argv
[1], "users")) {
534 target
= MESSAGE_RECIPIENT_LUSERS
;
535 } else if(!irccasecmp(argv
[1], "authed")) {
536 target
= MESSAGE_RECIPIENT_AUTHED
;
537 } else if(!irccasecmp(argv
[1], "helpers")) {
538 target
= MESSAGE_RECIPIENT_HELPERS
;
539 } else if(!irccasecmp(argv
[1], "opers")) {
540 target
= MESSAGE_RECIPIENT_OPERS
;
541 } else if(!irccasecmp(argv
[1], "staff") || !irccasecmp(argv
[1], "privileged")) {
542 target
|= MESSAGE_RECIPIENT_HELPERS
| MESSAGE_RECIPIENT_OPERS
;
543 } else if(!irccasecmp(argv
[1], "announcement") || !irccasecmp(argv
[1], "announce")) {
544 target
|= MESSAGE_RECIPIENT_ANNOUNCE
;
545 } else if(!irccasecmp(argv
[1], "channels")) {
546 target
= MESSAGE_RECIPIENT_CHANNELS
;
547 } else if(!irccasecmp(argv
[1], "rchannels")) {
548 target
= MESSAGE_RECIPIENT_RCHANNELS
;
550 global_notice(user
, "GMSG_INVALID_TARGET", argv
[1]);
553 if(!irccasecmp(argv
[2], "from")) {
555 reply("MSG_MISSING_PARAMS", argv
[0]);
560 text
= unsplit_string(argv
+ 4, argc
- 4, NULL
);
562 text
= unsplit_string(argv
+ 2, argc
- 2, NULL
);
565 message
= message_add(target
| MESSAGE_OPTION_IMMEDIATE
, now
, 0, sender
, text
);
569 recipient
= messageType(message
);
570 message_send(message
);
571 message_del(message
);
573 global_notice(user
, "GMSG_MESSAGE_SENT", recipient
);
577 static GLOBAL_FUNC(cmd_message
)
579 struct globalMessage
*message
= NULL
;
580 const char *recipient
= NULL
;
583 message
= message_create(user
, argc
- 1, argv
+ 1);
586 recipient
= messageType(message
);
587 global_notice(user
, "GMSG_MESSAGE_ADDED", recipient
, message
->id
);
591 static GLOBAL_FUNC(cmd_list
)
593 struct globalMessage
*message
;
594 struct helpfile_table table
;
595 unsigned int length
, nn
;
599 global_notice(user
, "GMSG_NO_MESSAGES");
603 for(nn
=0, message
= messageList
; message
; nn
++, message
=message
->next
) ;
606 table
.flags
= TABLE_NO_FREE
;
607 table
.contents
= calloc(table
.length
, sizeof(char**));
608 table
.contents
[0] = calloc(table
.width
, sizeof(char*));
609 table
.contents
[0][0] = "ID";
610 table
.contents
[0][1] = "Target";
611 table
.contents
[0][2] = "Expires";
612 table
.contents
[0][3] = "From";
613 table
.contents
[0][4] = "Message";
615 for(nn
=1, message
= messageList
; message
; nn
++, message
= message
->next
)
619 table
.contents
[nn
] = calloc(table
.width
, sizeof(char*));
620 snprintf(buffer
, sizeof(buffer
), "%lu", message
->id
);
621 table
.contents
[nn
][0] = strdup(buffer
);
622 table
.contents
[nn
][1] = messageType(message
);
623 if(message
->duration
)
624 intervalString(buffer
, message
->posted
+ message
->duration
- now
, user
->handle_info
);
626 strcpy(buffer
, "Never.");
627 table
.contents
[nn
][2] = strdup(buffer
);
628 table
.contents
[nn
][3] = message
->from
;
629 length
= strlen(message
->message
);
630 safestrncpy(buffer
, message
->message
, sizeof(buffer
));
631 if(length
> (sizeof(buffer
) - 4))
633 buffer
[sizeof(buffer
) - 1] = 0;
634 buffer
[sizeof(buffer
) - 2] = buffer
[sizeof(buffer
) - 3] = buffer
[sizeof(buffer
) - 4] = '.';
636 table
.contents
[nn
][4] = strdup(buffer
);
638 table_send(global
, user
->nick
, 0, NULL
, table
);
639 for (nn
=1; nn
<table
.length
; nn
++)
641 free((char*)table
.contents
[nn
][0]);
642 free((char*)table
.contents
[nn
][2]);
643 free((char*)table
.contents
[nn
][4]);
644 free(table
.contents
[nn
]);
646 free(table
.contents
[0]);
647 free(table
.contents
);
652 static GLOBAL_FUNC(cmd_remove
)
654 struct globalMessage
*message
= NULL
;
658 id
= strtoul(argv
[1], NULL
, 0);
660 for(message
= messageList
; message
; message
= message
->next
)
662 if(message
->id
== id
)
664 message_del(message
);
665 global_notice(user
, "GMSG_MESSAGE_DELETED", argv
[1]);
670 global_notice(user
, "GMSG_ID_INVALID", argv
[1]);
675 send_messages(struct userNode
*user
, long mask
, int obstreperize
)
677 struct globalMessage
*message
= messageList
;
678 unsigned int count
= 0;
682 if(message
->flags
& mask
)
684 if (obstreperize
&& !count
)
686 send_target_message(0, user
->nick
, global
, "GMSG_MOTD_HEADER");
687 send_target_message(0, user
->nick
, global
, "GMSG_MOTD_BAR");
689 notice_target(user
->nick
, message
);
693 message
= message
->next
;
695 if (obstreperize
&& count
)
696 send_target_message(0, user
->nick
, global
, "GMSG_MOTD_FOOTER");
700 static GLOBAL_FUNC(cmd_messages
)
702 long mask
= MESSAGE_RECIPIENT_AUTHED
| MESSAGE_RECIPIENT_LUSERS
| MESSAGE_RECIPIENT_CHANNELS
| MESSAGE_RECIPIENT_RCHANNELS
;
706 mask
|= MESSAGE_RECIPIENT_OPERS
;
709 mask
|= MESSAGE_RECIPIENT_HELPERS
;
711 count
= send_messages(user
, mask
, 0);
713 global_notice(user
, "GMSG_MESSAGE_COUNT", count
);
715 global_notice(user
, "GMSG_NO_MESSAGES");
721 global_process_user(struct userNode
*user
, UNUSED_ARG(void *extra
))
723 if(IsLocal(user
) || self
->uplink
->burst
|| user
->uplink
->burst
)
725 send_messages(user
, MESSAGE_RECIPIENT_LUSERS
, 1);
727 /* only alert on new usercount if the record was broken in the last
728 * 30 seconds, and no alert had been sent in that time.
730 if((now
- max_clients_time
) <= 30 && (now
- last_max_alert
) > 30)
733 message
= alloca(36);
734 sprintf(message
, "New user count record: %d", max_clients
);
735 global_message(MESSAGE_RECIPIENT_OPERS
, message
);
736 last_max_alert
= now
;
743 global_process_auth(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
), UNUSED_ARG(void *extra
))
746 send_messages(user
, MESSAGE_RECIPIENT_HELPERS
, 0);
750 global_process_oper(struct userNode
*user
, UNUSED_ARG(void *extra
))
752 if(user
->uplink
->burst
)
754 send_messages(user
, MESSAGE_RECIPIENT_OPERS
, 0);
758 global_conf_read(void)
763 if (!(conf_node
= conf_get_data(GLOBAL_CONF_NAME
, RECDB_OBJECT
))) {
764 log_module(G_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", GLOBAL_CONF_NAME
);
768 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
769 global_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
770 str
= database_get_data(conf_node
, KEY_ANNOUNCEMENTS_DEFAULT
, RECDB_QSTRING
);
771 global_conf
.announcements_default
= str
? enabled_string(str
) : 1;
773 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
775 NickChange(global
, str
, 0);
779 global_saxdb_read(struct dict
*db
)
781 struct record_data
*hir
;
784 unsigned long duration
;
785 char *str
, *from
, *message
;
788 for(it
=dict_first(db
); it
; it
=iter_next(it
))
791 if(hir
->type
!= RECDB_OBJECT
)
793 log_module(G_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s.", hir
->type
, iter_key(it
));
797 str
= database_get_data(hir
->d
.object
, KEY_FLAGS
, RECDB_QSTRING
);
798 flags
= str
? strtoul(str
, NULL
, 0) : 0;
800 str
= database_get_data(hir
->d
.object
, KEY_POSTED
, RECDB_QSTRING
);
801 posted
= str
? strtoul(str
, NULL
, 0) : 0;
803 str
= database_get_data(hir
->d
.object
, KEY_DURATION
, RECDB_QSTRING
);
804 duration
= str
? strtoul(str
, NULL
, 0) : 0;
806 from
= database_get_data(hir
->d
.object
, KEY_FROM
, RECDB_QSTRING
);
807 message
= database_get_data(hir
->d
.object
, KEY_MESSAGE
, RECDB_QSTRING
);
809 message_add(flags
, posted
, duration
, from
, message
);
815 global_saxdb_write(struct saxdb_context
*ctx
)
817 struct globalMessage
*message
;
820 for(message
= messageList
; message
; message
= message
->next
) {
821 snprintf(str
, sizeof(str
), "%li", message
->id
);
822 saxdb_start_record(ctx
, str
, 0);
823 saxdb_write_int(ctx
, KEY_FLAGS
, message
->flags
);
824 saxdb_write_int(ctx
, KEY_POSTED
, message
->posted
);
825 saxdb_write_int(ctx
, KEY_DURATION
, message
->duration
);
826 saxdb_write_string(ctx
, KEY_FROM
, message
->from
);
827 saxdb_write_string(ctx
, KEY_MESSAGE
, message
->message
);
828 saxdb_end_record(ctx
);
834 global_db_cleanup(UNUSED_ARG(void *extra
))
837 message_del(messageList
);
841 init_global(const char *nick
)
843 struct chanNode
*chan
;
845 G_LOG
= log_register_type("Global", "file:global.log");
846 reg_new_user_func(global_process_user
, NULL
);
847 reg_auth_func(global_process_auth
, NULL
);
848 reg_oper_func(global_process_oper
, NULL
);
850 conf_register_reload(global_conf_read
);
852 global_module
= module_register("Global", G_LOG
, "global.help", NULL
);
853 modcmd_register(global_module
, "LIST", cmd_list
, 1, 0, "flags", "+oper", NULL
);
854 modcmd_register(global_module
, "MESSAGE", cmd_message
, 3, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
855 modcmd_register(global_module
, "MESSAGES", cmd_messages
, 1, 0, NULL
);
856 modcmd_register(global_module
, "NOTICE", cmd_notice
, 3, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
857 modcmd_register(global_module
, "REMOVE", cmd_remove
, 2, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
861 const char *modes
= conf_get_data("services/global/modes", RECDB_QSTRING
);
862 global
= AddLocalUser(nick
, nick
, NULL
, "Global Services", modes
);
863 global_service
= service_register(global
);
866 if(autojoin_channels
&& global
) {
867 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
868 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
869 AddChannelUser(global
, chan
)->modes
|= MODE_CHANOP
;
873 saxdb_register("Global", global_saxdb_read
, global_saxdb_write
);
874 reg_exit_func(global_db_cleanup
, NULL
);
875 message_register_table(msgtab
);