4 * Citadel Dynamic Loading Module
5 * Written by Brian Costello <btx@calyx.net>
24 #include <sys/types.h>
32 #include "dynloader.h"
33 #include "sysdep_decls.h"
43 struct LogFunctionHook *LogHookTable = NULL;
44 struct CleanupFunctionHook *CleanupHookTable = NULL;
45 struct SessionFunctionHook *SessionHookTable = NULL;
46 struct UserFunctionHook *UserHookTable = NULL;
47 struct XmsgFunctionHook *XmsgHookTable = NULL;
48 struct MessageFunctionHook *MessageHookTable = NULL;
49 struct NetprocFunctionHook *NetprocHookTable = NULL;
50 struct DeleteFunctionHook *DeleteHookTable = NULL;
51 struct ServiceFunctionHook *ServiceHookTable = NULL;
53 struct ProtoFunctionHook {
54 void (*handler) (char *cmdbuf);
57 struct ProtoFunctionHook *next;
58 } *ProtoHookList = NULL;
60 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
62 struct ProtoFunctionHook *p;
64 p = (struct ProtoFunctionHook *)
65 mallok(sizeof(struct ProtoFunctionHook));
68 fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
74 p->next = ProtoHookList;
76 lprintf(5, "Registered server command %s (%s)\n", cmd, desc);
80 void CtdlUnregisterProtoHook(void (*handler) (char *), char *cmd)
82 struct ProtoFunctionHook *cur, *p;
84 for (cur = ProtoHookList; cur != NULL; cur = cur->next) {
85 /* This will also remove duplicates if any */
87 handler == cur->handler &&
88 !strcmp(cmd, cur->cmd)) {
89 lprintf(5, "Unregistered server command %s (%s)\n",
92 if (cur == ProtoHookList) {
102 int DLoader_Exec_Cmd(char *cmdbuf)
104 struct ProtoFunctionHook *p;
106 for (p = ProtoHookList; p; p = p->next) {
107 if (!strncasecmp(cmdbuf, p->cmd, 4)) {
108 p->handler(&cmdbuf[5]);
115 void DLoader_Init(char *pathname)
122 char *(*h_init_fcn) (void);
125 char pathbuf[PATH_MAX];
127 if ((dir = opendir(pathname)) == NULL) {
131 while ((dptr = readdir(dir)) != NULL) {
132 if (strlen(dptr->d_name) < 4)
135 if (strcasecmp(&dptr->d_name[strlen(dptr->d_name)-3], ".so"))
137 if (strcasecmp(&dptr->d_name[strlen(dptr->d_name)-4], ".dll"))
141 snprintf(pathbuf, PATH_MAX, "%s/%s", pathname, dptr->d_name);
142 lprintf(7, "Initializing %s...\n", pathbuf);
145 if (!(fcn_handle = dlopen(pathbuf, RTLD_LAZY)))
147 if (!(fcn_handle = dlopen(pathbuf, DL_LAZY)))
150 safestrncpy(dl_error, dlerror(), sizeof dl_error);
151 for (i=0; i<strlen(dl_error); ++i)
152 if (!isprint(dl_error[i]))
154 fprintf(stderr, "DLoader_Init dlopen failed: %s\n",
158 h_init_fcn = (char * (*)(void))
160 dlsym(fcn_handle, "Dynamic_Module_Init");
162 dlsym(fcn_handle, "_Dynamic_Module_Init");
165 if (dlerror() != NULL) {
166 fprintf(stderr, "DLoader_Init dlsym failed\n");
169 dl_info = h_init_fcn();
171 lprintf(3, "Loaded module: %s\n", dl_info);
177 void CtdlRegisterLogHook(void (*fcn_ptr) (char *), int loglevel)
180 struct LogFunctionHook *newfcn;
182 newfcn = (struct LogFunctionHook *)
183 mallok(sizeof(struct LogFunctionHook));
184 newfcn->next = LogHookTable;
185 newfcn->h_function_pointer = fcn_ptr;
186 newfcn->loglevel = loglevel;
187 LogHookTable = newfcn;
189 lprintf(5, "Registered a new logging function\n");
193 void CtdlUnregisterLogHook(void (*fcn_ptr) (char *), int loglevel)
195 struct LogFunctionHook *cur, *p;
197 for (cur = LogHookTable; cur != NULL; cur = cur->next) {
198 /* This will also remove duplicates if any */
199 while (cur != NULL &&
200 fcn_ptr == cur->h_function_pointer &&
201 loglevel == cur->loglevel) {
202 lprintf(5, "Unregistered logging function\n");
204 if (cur == LogHookTable) {
214 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
217 struct CleanupFunctionHook *newfcn;
219 newfcn = (struct CleanupFunctionHook *)
220 mallok(sizeof(struct CleanupFunctionHook));
221 newfcn->next = CleanupHookTable;
222 newfcn->h_function_pointer = fcn_ptr;
223 CleanupHookTable = newfcn;
225 lprintf(5, "Registered a new cleanup function\n");
229 void CtdlUnregisterCleanupHook(void (*fcn_ptr) (void))
231 struct CleanupFunctionHook *cur, *p;
233 for (cur = CleanupHookTable; cur != NULL; cur = cur->next) {
234 /* This will also remove duplicates if any */
235 while (cur != NULL &&
236 fcn_ptr == cur->h_function_pointer) {
237 lprintf(5, "Unregistered cleanup function\n");
239 if (cur == CleanupHookTable) {
240 CleanupHookTable = p;
249 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType)
252 struct SessionFunctionHook *newfcn;
254 newfcn = (struct SessionFunctionHook *)
255 mallok(sizeof(struct SessionFunctionHook));
256 newfcn->next = SessionHookTable;
257 newfcn->h_function_pointer = fcn_ptr;
258 newfcn->eventtype = EventType;
259 SessionHookTable = newfcn;
261 lprintf(5, "Registered a new session function (type %d)\n",
266 void CtdlUnregisterSessionHook(void (*fcn_ptr) (void), int EventType)
268 struct SessionFunctionHook *cur, *p;
270 for (cur = SessionHookTable; cur != NULL; cur = cur->next) {
271 /* This will also remove duplicates if any */
272 while (cur != NULL &&
273 fcn_ptr == cur->h_function_pointer &&
274 EventType == cur->eventtype) {
275 lprintf(5, "Unregistered session function (type %d)\n",
278 if (cur == SessionHookTable) {
279 SessionHookTable = p;
288 void CtdlRegisterUserHook(void (*fcn_ptr) (char *, long), int EventType)
291 struct UserFunctionHook *newfcn;
293 newfcn = (struct UserFunctionHook *)
294 mallok(sizeof(struct UserFunctionHook));
295 newfcn->next = UserHookTable;
296 newfcn->h_function_pointer = fcn_ptr;
297 newfcn->eventtype = EventType;
298 UserHookTable = newfcn;
300 lprintf(5, "Registered a new user function (type %d)\n",
305 void CtdlUnregisterUserHook(void (*fcn_ptr) (char *, long), int EventType)
307 struct UserFunctionHook *cur, *p;
309 for (cur = UserHookTable; cur != NULL; cur = cur->next) {
310 /* This will also remove duplicates if any */
311 while (cur != NULL &&
312 fcn_ptr == cur->h_function_pointer &&
313 EventType == cur->eventtype) {
314 lprintf(5, "Unregistered user function (type %d)\n",
317 if (cur == UserHookTable) {
327 void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *),
331 struct MessageFunctionHook *newfcn;
333 newfcn = (struct MessageFunctionHook *)
334 mallok(sizeof(struct MessageFunctionHook));
335 newfcn->next = MessageHookTable;
336 newfcn->h_function_pointer = handler;
337 newfcn->eventtype = EventType;
338 MessageHookTable = newfcn;
340 lprintf(5, "Registered a new message function (type %d)\n",
345 void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *),
348 struct MessageFunctionHook *cur, *p;
350 for (cur = MessageHookTable; cur != NULL; cur = cur->next) {
351 /* This will also remove duplicates if any */
352 while (cur != NULL &&
353 handler == cur->h_function_pointer &&
354 EventType == cur->eventtype) {
355 lprintf(5, "Unregistered message function (type %d)\n",
358 if (cur == MessageHookTable) {
359 MessageHookTable = p;
368 void CtdlRegisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
370 struct NetprocFunctionHook *newfcn;
372 newfcn = (struct NetprocFunctionHook *)
373 mallok(sizeof(struct NetprocFunctionHook));
374 newfcn->next = NetprocHookTable;
375 newfcn->h_function_pointer = handler;
376 NetprocHookTable = newfcn;
378 lprintf(5, "Registered a new netproc function\n");
382 void CtdlUnregisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
384 struct NetprocFunctionHook *cur, *p;
386 for (cur = NetprocHookTable; cur != NULL; cur = cur->next) {
387 /* This will also remove duplicates if any */
388 while (cur != NULL &&
389 handler == cur->h_function_pointer ) {
390 lprintf(5, "Unregistered netproc function\n");
392 if (cur == NetprocHookTable) {
393 NetprocHookTable = p;
402 void CtdlRegisterDeleteHook(void (*handler)(char *, long) )
404 struct DeleteFunctionHook *newfcn;
406 newfcn = (struct DeleteFunctionHook *)
407 mallok(sizeof(struct DeleteFunctionHook));
408 newfcn->next = DeleteHookTable;
409 newfcn->h_function_pointer = handler;
410 DeleteHookTable = newfcn;
412 lprintf(5, "Registered a new netproc function\n");
416 void CtdlUnregisterDeleteHook(void (*handler)(char *, long) )
418 struct DeleteFunctionHook *cur, *p;
420 for (cur = DeleteHookTable; cur != NULL; cur = cur->next) {
421 /* This will also remove duplicates if any */
422 while (cur != NULL &&
423 handler == cur->h_function_pointer ) {
424 lprintf(5, "Unregistered netproc function\n");
426 if (cur == DeleteHookTable) {
436 void CtdlRegisterXmsgHook(int (*fcn_ptr) (char *, char *, char *), int order)
439 struct XmsgFunctionHook *newfcn;
441 newfcn = (struct XmsgFunctionHook *)
442 mallok(sizeof(struct XmsgFunctionHook));
443 newfcn->next = XmsgHookTable;
444 newfcn->order = order;
445 newfcn->h_function_pointer = fcn_ptr;
446 XmsgHookTable = newfcn;
447 lprintf(5, "Registered a new x-msg function (priority %d)\n", order);
451 void CtdlUnregisterXmsgHook(int (*fcn_ptr) (char *, char *, char *), int order)
453 struct XmsgFunctionHook *cur, *p;
455 for (cur = XmsgHookTable; cur != NULL; cur = cur->next) {
456 /* This will also remove duplicates if any */
457 while (cur != NULL &&
458 fcn_ptr == cur->h_function_pointer &&
459 order == cur->order) {
460 lprintf(5, "Unregistered x-msg function "
461 "(priority %d)\n", order);
463 if (cur == XmsgHookTable) {
473 void CtdlRegisterServiceHook(int tcp_port,
475 void (*h_greeting_function) (void),
476 void (*h_command_function) (void) )
478 struct ServiceFunctionHook *newfcn;
481 newfcn = (struct ServiceFunctionHook *)
482 mallok(sizeof(struct ServiceFunctionHook));
483 newfcn->next = ServiceHookTable;
484 newfcn->tcp_port = tcp_port;
485 newfcn->sockpath = sockpath;
486 newfcn->h_greeting_function = h_greeting_function;
487 newfcn->h_command_function = h_command_function;
489 if (sockpath != NULL) {
490 newfcn->msock = ig_uds_server(sockpath, config.c_maxsessions);
491 snprintf(message, sizeof message, "Unix domain socket '%s': ", sockpath);
493 else if (tcp_port <= 0) { /* port -1 to disable */
494 lprintf(7, "Service has been manually disabled, skipping\n");
499 newfcn->msock = ig_tcp_server(tcp_port, config.c_maxsessions);
500 snprintf(message, sizeof message, "TCP port %d: ", tcp_port);
503 if (newfcn->msock > 0) {
504 ServiceHookTable = newfcn;
505 strcat(message, "registered.");
506 lprintf(5, "%s\n", message);
509 strcat(message, "FAILED.");
510 lprintf(2, "%s\n", message);
516 void CtdlUnregisterServiceHook(int tcp_port, char *sockpath,
517 void (*h_greeting_function) (void),
518 void (*h_command_function) (void) )
520 struct ServiceFunctionHook *cur, *p;
522 for (cur = ServiceHookTable; cur != NULL; cur = cur->next) {
523 /* This will also remove duplicates if any */
524 while (cur != NULL &&
525 !(sockpath && cur->sockpath &&
526 strcmp(sockpath, cur->sockpath)) &&
527 h_greeting_function == cur->h_greeting_function &&
528 h_command_function == cur->h_command_function &&
529 tcp_port == cur->tcp_port) {
532 lprintf(5, "Closed UNIX domain socket %s\n",
534 } else if (tcp_port) {
535 lprintf(5, "Closed TCP port %d\n", tcp_port);
537 lprintf(5, "Unregistered unknown service\n");
540 if (cur == ServiceHookTable) {
541 ServiceHookTable = p;
550 void PerformSessionHooks(int EventType)
552 struct SessionFunctionHook *fcn;
554 for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
555 if (fcn->eventtype == EventType) {
556 (*fcn->h_function_pointer) ();
561 void PerformLogHooks(int loglevel, char *logmsg)
563 struct LogFunctionHook *fcn;
565 for (fcn = LogHookTable; fcn != NULL; fcn = fcn->next) {
566 if (fcn->loglevel >= loglevel) {
567 (*fcn->h_function_pointer) (logmsg);
572 void PerformUserHooks(char *username, long usernum, int EventType)
574 struct UserFunctionHook *fcn;
576 for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
577 if (fcn->eventtype == EventType) {
578 (*fcn->h_function_pointer) (username, usernum);
583 int PerformMessageHooks(struct CtdlMessage *msg, int EventType)
585 struct MessageFunctionHook *fcn;
586 int total_retval = 0;
588 /* Other code may elect to protect this message from server-side
589 * handlers; if this is the case, don't do anything.
590 lprintf(9, "** Event type is %d, flags are %d\n",
591 EventType, msg->cm_flags);
593 if (msg->cm_flags & CM_SKIP_HOOKS) {
594 lprintf(9, "Skipping hooks\n");
598 /* Otherwise, run all the hooks appropriate to this event type.
600 for (fcn = MessageHookTable; fcn != NULL; fcn = fcn->next) {
601 if (fcn->eventtype == EventType) {
602 total_retval = total_retval +
603 (*fcn->h_function_pointer) (msg);
607 /* Return the sum of the return codes from the hook functions. If
608 * this is an EVT_BEFORESAVE event, a nonzero return code will cause
609 * the save operation to abort.
616 int PerformNetprocHooks(struct CtdlMessage *msg, char *target_room)
618 struct NetprocFunctionHook *fcn;
619 int total_retval = 0;
621 for (fcn = NetprocHookTable; fcn != NULL; fcn = fcn->next) {
622 total_retval = total_retval +
623 (*fcn->h_function_pointer) (msg, target_room);
626 /* Return the sum of the return codes from the hook functions.
627 * A nonzero return code will cause the message to *not* be imported.
633 void PerformDeleteHooks(char *room, long msgnum)
635 struct DeleteFunctionHook *fcn;
637 for (fcn = DeleteHookTable; fcn != NULL; fcn = fcn->next) {
638 (*fcn->h_function_pointer) (room, msgnum);
644 int PerformXmsgHooks(char *sender, char *recp, char *msg)
646 struct XmsgFunctionHook *fcn;
650 for (p=0; p<MAX_XMSG_PRI; ++p) {
651 for (fcn = XmsgHookTable; fcn != NULL; fcn = fcn->next) {
652 if (fcn->order == p) {
654 (*fcn->h_function_pointer)
658 /* Break out of the loop if a higher-priority function
659 * successfully delivered the message. This prevents duplicate
660 * deliveries to local users simultaneously signed onto
663 if (total_sent) break;