]> code.citadel.org Git - citadel.git/blob - citadel/dynloader.c
* dynloader.c: fixed improperly done declaration and mallok()
[citadel.git] / citadel / dynloader.c
1 /*
2  * $Id$
3  *
4  * Citadel Dynamic Loading Module
5  * Written by Brian Costello <btx@calyx.net>
6  *
7  */
8
9 #ifdef DLL_EXPORT
10 #define IN_LIBCIT
11 #endif
12
13 #include "sysdep.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #ifdef HAVE_DLFCN_H
17 #include <dlfcn.h>
18 #endif
19 #ifdef HAVE_DL_H
20 #include <dl.h>
21 #include "hpsux.h"
22 #endif
23 #include <sys/types.h>
24 #include <dirent.h>
25 #include <string.h>
26 #include <syslog.h>
27 #include <limits.h>
28 #include <ctype.h>
29 #include "citadel.h"
30 #include "server.h"
31 #include "dynloader.h"
32 #include "sysdep_decls.h"
33 #include "msgbase.h"
34 #include "tools.h"
35 #include "config.h"
36
37 #ifndef HAVE_SNPRINTF
38 #include <stdarg.h>
39 #include "snprintf.h"
40 #endif
41
42 struct LogFunctionHook *LogHookTable = NULL;
43 struct CleanupFunctionHook *CleanupHookTable = NULL;
44 struct SessionFunctionHook *SessionHookTable = NULL;
45 struct UserFunctionHook *UserHookTable = NULL;
46 struct XmsgFunctionHook *XmsgHookTable = NULL;
47 struct MessageFunctionHook *MessageHookTable = NULL;
48 struct ServiceFunctionHook *ServiceHookTable = NULL;
49
50 struct ProtoFunctionHook {
51         void (*handler) (char *cmdbuf);
52         char *cmd;
53         char *desc;
54         struct ProtoFunctionHook *next;
55 } *ProtoHookList = NULL;
56
57 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
58 {
59         struct ProtoFunctionHook *p;
60
61         p = (struct ProtoFunctionHook *)
62                 mallok(sizeof(struct ProtoFunctionHook));
63
64         if (p == NULL) {
65                 fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
66                 exit(EXIT_FAILURE);
67         }
68         p->handler = handler;
69         p->cmd = cmd;
70         p->desc = desc;
71         p->next = ProtoHookList;
72         ProtoHookList = p;
73         lprintf(5, "Registered server command %s (%s)\n", cmd, desc);
74 }
75
76 int DLoader_Exec_Cmd(char *cmdbuf)
77 {
78         struct ProtoFunctionHook *p;
79
80         for (p = ProtoHookList; p; p = p->next) {
81                 if (!strncasecmp(cmdbuf, p->cmd, 4)) {
82                         p->handler(&cmdbuf[5]);
83                         return 1;
84                 }
85         }
86         return 0;
87 }
88
89 void DLoader_Init(char *pathname)
90 {
91         void *fcn_handle;
92         char dl_error[SIZ];
93         DIR *dir;
94         int i;
95         struct dirent *dptr;
96         char *(*h_init_fcn) (void);
97         char *dl_info;
98
99         char pathbuf[PATH_MAX];
100
101         if ((dir = opendir(pathname)) == NULL) {
102                 perror("opendir");
103                 exit(1);
104         }
105         while ((dptr = readdir(dir)) != NULL) {
106                 if (strlen(dptr->d_name) < 4)
107                         continue;
108 #ifndef __CYGWIN__
109                 if (strcasecmp(&dptr->d_name[strlen(dptr->d_name)-3], ".so"))
110 #else
111                 if (strcasecmp(&dptr->d_name[strlen(dptr->d_name)-4], ".dll"))
112 #endif
113                         continue;
114
115                 snprintf(pathbuf, PATH_MAX, "%s/%s", pathname, dptr->d_name);
116                 lprintf(7, "Initializing %s...\n", pathbuf);
117
118 #ifdef RTLD_LAZY
119                 if (!(fcn_handle = dlopen(pathbuf, RTLD_LAZY)))
120 #else                           /* OpenBSD */
121                 if (!(fcn_handle = dlopen(pathbuf, DL_LAZY)))
122 #endif
123                 {
124                         safestrncpy(dl_error, dlerror(), sizeof dl_error);
125                         for (i=0; i<strlen(dl_error); ++i)
126                                 if (!isprint(dl_error[i]))
127                                         dl_error[i]='.';
128                         fprintf(stderr, "DLoader_Init dlopen failed: %s\n",
129                                 dl_error);
130                         continue;
131                 }
132                 h_init_fcn = (char * (*)(void))
133 #ifndef __OpenBSD__
134                     dlsym(fcn_handle, "Dynamic_Module_Init");
135 #else
136                     dlsym(fcn_handle, "_Dynamic_Module_Init");
137 #endif
138
139                 if (dlerror() != NULL) {
140                         fprintf(stderr, "DLoader_Init dlsym failed\n");
141                         continue;
142                 }
143                 dl_info = h_init_fcn();
144
145                 lprintf(3, "Loaded module: %s\n", dl_info);
146         }       /* While */
147 }
148
149
150
151 void CtdlRegisterLogHook(void (*fcn_ptr) (char *), int loglevel)
152 {
153
154         struct LogFunctionHook *newfcn;
155
156         newfcn = (struct LogFunctionHook *)
157             mallok(sizeof(struct LogFunctionHook));
158         newfcn->next = LogHookTable;
159         newfcn->h_function_pointer = fcn_ptr;
160         newfcn->loglevel = loglevel;
161         LogHookTable = newfcn;
162
163         lprintf(5, "Registered a new logging function\n");
164 }
165
166
167 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
168 {
169
170         struct CleanupFunctionHook *newfcn;
171
172         newfcn = (struct CleanupFunctionHook *)
173             mallok(sizeof(struct CleanupFunctionHook));
174         newfcn->next = CleanupHookTable;
175         newfcn->h_function_pointer = fcn_ptr;
176         CleanupHookTable = newfcn;
177
178         lprintf(5, "Registered a new cleanup function\n");
179 }
180
181
182 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType)
183 {
184
185         struct SessionFunctionHook *newfcn;
186
187         newfcn = (struct SessionFunctionHook *)
188             mallok(sizeof(struct SessionFunctionHook));
189         newfcn->next = SessionHookTable;
190         newfcn->h_function_pointer = fcn_ptr;
191         newfcn->eventtype = EventType;
192         SessionHookTable = newfcn;
193
194         lprintf(5, "Registered a new session function (type %d)\n",
195                 EventType);
196 }
197
198
199 void CtdlRegisterUserHook(void (*fcn_ptr) (char *, long), int EventType)
200 {
201
202         struct UserFunctionHook *newfcn;
203
204         newfcn = (struct UserFunctionHook *)
205             mallok(sizeof(struct UserFunctionHook));
206         newfcn->next = UserHookTable;
207         newfcn->h_function_pointer = fcn_ptr;
208         newfcn->eventtype = EventType;
209         UserHookTable = newfcn;
210
211         lprintf(5, "Registered a new user function (type %d)\n",
212                 EventType);
213 }
214
215
216 void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *),
217                                 int EventType)
218 {
219
220         struct MessageFunctionHook *newfcn;
221
222         newfcn = (struct MessageFunctionHook *)
223             mallok(sizeof(struct MessageFunctionHook));
224         newfcn->next = MessageHookTable;
225         newfcn->h_function_pointer = handler;
226         newfcn->eventtype = EventType;
227         MessageHookTable = newfcn;
228
229         lprintf(5, "Registered a new message function (type %d)\n",
230                 EventType);
231 }
232
233
234 void CtdlRegisterXmsgHook(int (*fcn_ptr) (char *, char *, char *), int order)
235 {
236
237         struct XmsgFunctionHook *newfcn;
238
239         newfcn = (struct XmsgFunctionHook *)
240             mallok(sizeof(struct XmsgFunctionHook));
241         newfcn->next = XmsgHookTable;
242         newfcn->order = order;
243         newfcn->h_function_pointer = fcn_ptr;
244         XmsgHookTable = newfcn;
245         lprintf(5, "Registered a new x-msg function (priority %d)\n", order);
246 }
247
248 void CtdlRegisterServiceHook(int tcp_port,
249                         char *sockpath,
250                         void (*h_greeting_function) (void),
251                         void (*h_command_function) (void) )
252 {
253         struct ServiceFunctionHook *newfcn;
254         char message[SIZ];
255
256         newfcn = (struct ServiceFunctionHook *)
257             mallok(sizeof(struct ServiceFunctionHook));
258         newfcn->next = ServiceHookTable;
259         newfcn->tcp_port = tcp_port;
260         newfcn->sockpath = sockpath;
261         newfcn->h_greeting_function = h_greeting_function;
262         newfcn->h_command_function = h_command_function;
263
264         if (sockpath != NULL) {
265                 newfcn->msock = ig_uds_server(sockpath, config.c_maxsessions);
266                 sprintf(message, "Unix domain socket '%s': ", sockpath);
267         }
268         else if (tcp_port <= 0) {       /* port -1 to disable */
269                 lprintf(7, "Service has been manually disabled, skipping\n");
270                 phree(newfcn);
271                 return;
272         }
273         else {
274                 newfcn->msock = ig_tcp_server(tcp_port, config.c_maxsessions);
275                 sprintf(message, "TCP port %d: ", tcp_port);
276         }
277
278         if (newfcn->msock > 0) {
279                 ServiceHookTable = newfcn;
280                 strcat(message, "registered.");
281                 lprintf(5, "%s\n", message);
282         }
283         else {
284                 strcat(message, "FAILED.");
285                 lprintf(2, "%s\n", message);
286                 phree(newfcn);
287         }
288 }
289
290
291
292 void PerformSessionHooks(int EventType)
293 {
294         struct SessionFunctionHook *fcn;
295
296         for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
297                 if (fcn->eventtype == EventType) {
298                         (*fcn->h_function_pointer) ();
299                 }
300         }
301 }
302
303 void PerformLogHooks(int loglevel, char *logmsg)
304 {
305         struct LogFunctionHook *fcn;
306
307         for (fcn = LogHookTable; fcn != NULL; fcn = fcn->next) {
308                 if (fcn->loglevel >= loglevel) {
309                         (*fcn->h_function_pointer) (logmsg);
310                 }
311         }
312 }
313
314 void PerformUserHooks(char *username, long usernum, int EventType)
315 {
316         struct UserFunctionHook *fcn;
317
318         for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
319                 if (fcn->eventtype == EventType) {
320                         (*fcn->h_function_pointer) (username, usernum);
321                 }
322         }
323 }
324
325 int PerformMessageHooks(struct CtdlMessage *msg, int EventType)
326 {
327         struct MessageFunctionHook *fcn;
328         int total_retval = 0;
329
330         /* Other code may elect to protect this message from server-side
331          * handlers; if this is the case, don't do anything.
332         lprintf(9, "** Event type is %d, flags are %d\n",
333                 EventType, msg->cm_flags);
334          */
335         if (msg->cm_flags & CM_SKIP_HOOKS) {
336                 lprintf(9, "Skipping hooks\n");
337                 return(0);
338         }
339
340         /* Otherwise, run all the hooks appropriate to this event type.
341          */
342         for (fcn = MessageHookTable; fcn != NULL; fcn = fcn->next) {
343                 if (fcn->eventtype == EventType) {
344                         total_retval = total_retval +
345                                 (*fcn->h_function_pointer) (msg);
346                 }
347         }
348
349         /* Return the sum of the return codes from the hook functions.  If
350          * this is an EVT_BEFORESAVE event, a nonzero return code will cause
351          * the save operation to abort.
352          */
353         return total_retval;
354 }
355
356
357
358 int PerformXmsgHooks(char *sender, char *recp, char *msg)
359 {
360         struct XmsgFunctionHook *fcn;
361         int total_sent = 0;
362         int p;
363
364         for (p=0; p<MAX_XMSG_PRI; ++p) {
365                 for (fcn = XmsgHookTable; fcn != NULL; fcn = fcn->next) {
366                         if (fcn->order == p) {
367                                 total_sent +=
368                                         (*fcn->h_function_pointer)
369                                                 (sender, recp, msg);
370                         }
371                 }
372                 /* Break out of the loop if a higher-priority function
373                  * successfully delivered the message.  This prevents duplicate
374                  * deliveries to local users simultaneously signed onto
375                  * remote services.
376                  */
377                 if (total_sent) goto DONE;
378         }
379 DONE:   return total_sent;
380 }