ICQ changes
[citadel.git] / citadel / dynloader.c
1 /*******************************************************
2  *
3  * Citadel Dynamic Loading Module
4  * Written by Brian Costello
5  * btx@calyx.net
6  *
7  * $Id$
8  *
9  ******************************************************/
10
11
12 #include "sysdep.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <dlfcn.h>
16 #include <sys/types.h>
17 #include <dirent.h>
18 #include <strings.h>
19 #include <syslog.h>
20 #ifdef HAVE_PTHREAD_H
21 #include <pthread.h>
22 #endif
23 #include <limits.h>
24 #include <ctype.h>
25 #include "dynloader.h"
26 #include "citadel.h"
27 #include "server.h"
28 #include "sysdep_decls.h"
29 #include "tools.h"
30
31 #ifndef HAVE_SNPRINTF
32 #include <stdarg.h>
33 #include "snprintf.h"
34 #endif
35
36 struct LogFunctionHook *LogHookTable = NULL;
37 struct CleanupFunctionHook *CleanupHookTable = NULL;
38 struct SessionFunctionHook *SessionHookTable = NULL;
39 struct UserFunctionHook *UserHookTable = NULL;
40 struct XmsgFunctionHook *XmsgHookTable = NULL;
41
42 struct ProtoFunctionHook {
43         void (*handler) (char *cmdbuf);
44         char *cmd;
45         char *desc;
46         struct ProtoFunctionHook *next;
47 } *ProtoHookList = NULL;
48
49 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
50 {
51         struct ProtoFunctionHook *p = mallok(sizeof *p);
52
53         if (p == NULL) {
54                 fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
55                 exit(EXIT_FAILURE);
56         }
57         p->handler = handler;
58         p->cmd = cmd;
59         p->desc = desc;
60         p->next = ProtoHookList;
61         ProtoHookList = p;
62         lprintf(5, "Registered server command %s (%s)\n", cmd, desc);
63 }
64
65 int DLoader_Exec_Cmd(char *cmdbuf)
66 {
67         struct ProtoFunctionHook *p;
68
69         for (p = ProtoHookList; p; p = p->next) {
70                 if (!strncasecmp(cmdbuf, p->cmd, 4)) {
71                         p->handler(&cmdbuf[5]);
72                         return 1;
73                 }
74         }
75         return 0;
76 }
77
78 void DLoader_Init(char *pathname)
79 {
80         void *fcn_handle;
81         char dl_error[256];
82         DIR *dir;
83         int i;
84         struct dirent *dptr;
85         char *(*h_init_fcn) (void);
86         char *dl_info;
87
88         char pathbuf[PATH_MAX];
89
90         if ((dir = opendir(pathname)) == NULL) {
91                 perror("opendir");
92                 exit(1);
93         }
94         while ((dptr = readdir(dir)) != NULL) {
95                 if (dptr->d_name[0] == '.')
96                         continue;
97
98                 snprintf(pathbuf, PATH_MAX, "%s/%s", pathname, dptr->d_name);
99 #ifdef RTLD_NOW
100                 if (!(fcn_handle = dlopen(pathbuf, RTLD_NOW)))
101 #else                           /* OpenBSD */
102                 if (!(fcn_handle = dlopen(pathbuf, DL_LAZY)))
103 #endif
104                 {
105                         safestrncpy(dl_error, dlerror(), sizeof dl_error);
106                         for (i=0; i<strlen(dl_error); ++i)
107                                 if (!isprint(dl_error[i]))
108                                         dl_error[i]='.';
109                         fprintf(stderr, "DLoader_Init dlopen failed: %s\n",
110                                 dl_error);
111                         continue;
112                 }
113                 h_init_fcn = (char * (*)(void))
114 #ifndef __OpenBSD__
115                     dlsym(fcn_handle, "Dynamic_Module_Init");
116 #else
117                     dlsym(fcn_handle, "_Dynamic_Module_Init");
118 #endif
119
120                 if (dlerror() != NULL) {
121                         fprintf(stderr, "DLoader_Init dlsym failed\n");
122                         continue;
123                 }
124                 dl_info = h_init_fcn();
125
126                 lprintf(3, "Loaded module: %s\n", dl_info);
127         }       /* While */
128 }
129
130
131
132 void CtdlRegisterLogHook(void (*fcn_ptr) (char *), int loglevel)
133 {
134
135         struct LogFunctionHook *newfcn;
136
137         newfcn = (struct LogFunctionHook *)
138             mallok(sizeof(struct LogFunctionHook));
139         newfcn->next = LogHookTable;
140         newfcn->h_function_pointer = fcn_ptr;
141         newfcn->loglevel = loglevel;
142         LogHookTable = newfcn;
143
144         lprintf(5, "Registered a new logging function\n");
145 }
146
147
148 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
149 {
150
151         struct CleanupFunctionHook *newfcn;
152
153         newfcn = (struct CleanupFunctionHook *)
154             mallok(sizeof(struct CleanupFunctionHook));
155         newfcn->next = CleanupHookTable;
156         newfcn->h_function_pointer = fcn_ptr;
157         CleanupHookTable = newfcn;
158
159         lprintf(5, "Registered a new cleanup function\n");
160 }
161
162
163 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType)
164 {
165
166         struct SessionFunctionHook *newfcn;
167
168         newfcn = (struct SessionFunctionHook *)
169             mallok(sizeof(struct SessionFunctionHook));
170         newfcn->next = SessionHookTable;
171         newfcn->h_function_pointer = fcn_ptr;
172         newfcn->eventtype = EventType;
173         SessionHookTable = newfcn;
174
175         lprintf(5, "Registered a new session function (type %d)\n",
176                 EventType);
177 }
178
179
180 void CtdlRegisterUserHook(void (*fcn_ptr) (char *, long), int EventType)
181 {
182
183         struct UserFunctionHook *newfcn;
184
185         newfcn = (struct UserFunctionHook *)
186             mallok(sizeof(struct UserFunctionHook));
187         newfcn->next = UserHookTable;
188         newfcn->h_function_pointer = fcn_ptr;
189         newfcn->eventtype = EventType;
190         UserHookTable = newfcn;
191
192         lprintf(5, "Registered a new user function (type %d)\n",
193                 EventType);
194 }
195
196
197 void CtdlRegisterXmsgHook(int (*fcn_ptr) (char *, char *, char *) )
198 {
199
200         struct XmsgFunctionHook *newfcn;
201
202         newfcn = (struct XmsgFunctionHook *)
203             mallok(sizeof(struct XmsgFunctionHook));
204         newfcn->next = XmsgHookTable;
205         newfcn->h_function_pointer = fcn_ptr;
206         XmsgHookTable = newfcn;
207
208         lprintf(5, "Registered a new x-msg function\n");
209 }
210
211
212 void PerformSessionHooks(int EventType)
213 {
214         struct SessionFunctionHook *fcn;
215
216         for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
217                 if (fcn->eventtype == EventType) {
218                         (*fcn->h_function_pointer) ();
219                 }
220         }
221 }
222
223 void PerformLogHooks(int loglevel, char *logmsg)
224 {
225         struct LogFunctionHook *fcn;
226
227         for (fcn = LogHookTable; fcn != NULL; fcn = fcn->next) {
228                 if (fcn->loglevel >= loglevel) {
229                         (*fcn->h_function_pointer) (logmsg);
230                 }
231         }
232 }
233
234 void PerformUserHooks(char *username, long usernum, int EventType)
235 {
236         struct UserFunctionHook *fcn;
237
238         for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
239                 if (fcn->eventtype == EventType) {
240                         (*fcn->h_function_pointer) (username, usernum);
241                 }
242         }
243 }
244
245 int PerformXmsgHooks(char *sender, char *recp, char *msg)
246 {
247         struct XmsgFunctionHook *fcn;
248         int total_sent = 0;
249
250         for (fcn = XmsgHookTable; fcn != NULL; fcn = fcn->next) {
251                 total_sent +=
252                         (*fcn->h_function_pointer) (sender, recp, msg);
253         }
254         return total_sent;
255 }