]> code.citadel.org Git - citadel.git/blob - citadel/serv_vcard.c
1b9a53b52d566464509e4194feb88b5ba43e1043
[citadel.git] / citadel / serv_vcard.c
1 /*
2  * serv_vcard.c
3  * 
4  * A server-side module for Citadel which supports address book information
5  * using the standard vCard format.
6  *
7  * $Id$
8  *
9  */
10
11 #define ADDRESS_BOOK_ROOM       "Global Address Book"
12
13 #include "sysdep.h"
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <pwd.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/wait.h>
24 #include <string.h>
25 #include <limits.h>
26 #ifdef HAVE_PTHREAD_H
27 #include <pthread.h>
28 #endif
29 #include "citadel.h"
30 #include "server.h"
31 #include <syslog.h>
32 #include <time.h>
33 #include "sysdep_decls.h"
34 #include "citserver.h"
35 #include "support.h"
36 #include "config.h"
37 #include "control.h"
38 #include "dynloader.h"
39 #include "room_ops.h"
40 #include "user_ops.h"
41 #include "policy.h"
42 #include "database.h"
43 #include "msgbase.h"
44 #include "tools.h"
45 #include "vcard.h"
46
47 struct vcard_internal_info {
48         long msgnum;
49 };
50
51 /* Message number symbol used internally by these functions */
52 unsigned long SYM_VCARD;
53 #define VC ((struct vcard_internal_info *)CtdlGetUserData(SYM_VCARD))
54
55
56 /*
57  * back end function used by vcard_personal_upload()
58  */
59 void vcard_replace_backend(long msgnum) {
60         lprintf(9, "doing the replace thing for <%ld>\n", msgnum);
61         CtdlDeleteMessages(CONFIGROOM, msgnum, NULL);
62         CtdlDeleteMessages(ADDRESS_BOOK_ROOM, msgnum, NULL);
63 }
64
65
66 /*
67  * This handler detects whether the user is attempting to save a new
68  * vCard as part of his/her personal configuration, and handles the replace
69  * function accordingly.
70  */
71 int vcard_personal_upload(struct CtdlMessage *msg) {
72         char *ptr;
73         int linelen;
74         char hold_rm[ROOMNAMELEN];
75         char config_rm[ROOMNAMELEN];
76
77         /* If this isn't the configuration room, or if this isn't a MIME
78          * message, don't bother.
79          */
80         if (strcasecmp(msg->cm_fields['O'], CONFIGROOM)) return(0);
81         if (msg->cm_format_type != 4) return(0);
82
83         ptr = msg->cm_fields['M'];
84         while (ptr != NULL) {
85         
86                 linelen = strcspn(ptr, "\n");
87                 if (linelen == 0) return(0);    /* end of headers */    
88                 
89                 if (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) {
90                         /* Bingo!  The user is uploading a new vCard, so
91                          * delete the old one.
92                          */
93
94                         strcpy(hold_rm, CC->quickroom.QRname);  /* save rm */
95                         MailboxName(config_rm, &CC->usersupp, CONFIGROOM);
96
97                         if (getroom(&CC->quickroom, config_rm) != 0) {
98                                 getroom(&CC->quickroom, hold_rm);
99                                 return(1);                      /* abort */
100                         }
101                         CtdlForEachMessage(MSGS_ALL, 0,
102                                 "text/x-vcard", vcard_replace_backend);
103                         getroom(&CC->quickroom, hold_rm);       /* return rm */
104                         return(0);
105                 }
106
107                 ptr = strchr((char *)ptr, '\n');
108                 if (ptr != NULL) ++ptr;
109         }
110
111         return(0);
112 }
113
114
115
116 /*
117  * back end function used by vcard_get_user()
118  */
119 void vcard_gm_backend(long msgnum) {
120         VC->msgnum = msgnum;
121 }
122
123
124 /*
125  * If this user has a vcard on disk, read it into memory, otherwise allocate
126  * and return an empty vCard.
127  */
128 struct vCard *vcard_get_user(struct usersupp *u) {
129         char hold_rm[ROOMNAMELEN];
130         char config_rm[ROOMNAMELEN];
131         struct CtdlMessage *msg;
132         struct vCard *v;
133
134         strcpy(hold_rm, CC->quickroom.QRname);  /* save current room */
135         MailboxName(config_rm, u, CONFIGROOM);
136
137         if (getroom(&CC->quickroom, config_rm) != 0) {
138                 getroom(&CC->quickroom, hold_rm);
139                 return vcard_new();
140         }
141
142         /* We want the last (and probably only) vcard in this room */
143         VC->msgnum = (-1);
144         CtdlForEachMessage(MSGS_LAST, 1, "text/x-vcard", vcard_gm_backend);
145         getroom(&CC->quickroom, hold_rm);       /* return to saved room */
146
147         if (VC->msgnum < 0L) return vcard_new();
148
149         msg = CtdlFetchMessage(VC->msgnum);
150         if (msg == NULL) return vcard_new();
151
152         v = vcard_load(msg->cm_fields['M']);
153         CtdlFreeMessage(msg);
154         return v;
155 }
156
157
158 /*
159  * Store this user's vCard in the appropriate place
160  */
161 /*
162  * Write our config to disk
163  */
164 void vcard_write_user(struct usersupp *u, struct vCard *v) {
165         char temp[PATH_MAX];
166         FILE *fp;
167         char *ser;
168
169         strcpy(temp, tmpnam(NULL));
170         ser = vcard_serialize(v);
171
172         fp = fopen(temp, "w");
173         if (fp == NULL) return;
174         fprintf(fp, "Content-type: text/x-vcard\r\n\r\n");
175         if (ser == NULL) {
176                 fprintf(fp, "begin:vcard\r\nend:vcard\r\n");
177         } else {
178                 fwrite(ser, strlen(ser), 1, fp);
179                 phree(ser);
180         }
181         fclose(fp);
182
183         /* This handy API function does all the work for us.
184          * NOTE: normally we would want to set that last argument to 1, to
185          * force the system to delete the user's old vCard.  But it doesn't
186          * have to, because the vcard_personal_upload() hook above is going to
187          * notice what we're trying to do, and delete the old vCard.
188          */
189         CtdlWriteObject(CONFIGROOM,     /* which room */
190                         "text/x-vcard", /* MIME type */
191                         temp,           /* temp file */
192                         u,              /* which user */
193                         0,              /* not binary */
194                         0);             /* don't delete others of this type */
195
196         unlink(temp);
197 }
198
199
200
201 /*
202  * old style "enter registration info" command
203  */
204 void cmd_regi(char *argbuf) {
205         int a,b,c;
206         char buf[256];
207         struct vCard *my_vcard;
208
209         char tmpaddr[256];
210         char tmpcity[256];
211         char tmpstate[256];
212         char tmpzip[256];
213         char tmpphone[256];
214         char tmpaddress[512];
215
216         if (!(CC->logged_in)) {
217                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
218                 return;
219                 }
220
221         my_vcard = vcard_get_user(&CC->usersupp);
222         strcpy(tmpaddr, "");
223         strcpy(tmpcity, "");
224         strcpy(tmpstate, "");
225         strcpy(tmpzip, "");
226
227         cprintf("%d Send registration...\n", SEND_LISTING);
228         a=0;
229         while (client_gets(buf), strcmp(buf,"000")) {
230                 if (a==0) vcard_set_prop(my_vcard, "n", buf);
231                 if (a==1) strcpy(tmpaddr,buf);
232                 if (a==2) strcpy(tmpcity,buf);
233                 if (a==3) strcpy(tmpstate,buf);
234                 if (a==4) {
235                         for (c=0; c<strlen(buf); ++c) {
236                                 if ((buf[c]>='0')&&(buf[c]<='9')) {
237                                         b=strlen(tmpzip);
238                                         tmpzip[b]=buf[c];
239                                         tmpzip[b+1]=0;
240                                         }
241                                 }
242                         }
243                 if (a==5) {
244                         strcpy(tmpphone, "");
245                         for (c=0; c<strlen(buf); ++c) {
246                                 if ((buf[c]>='0')&&(buf[c]<='9')) {
247                                         b=strlen(tmpphone);
248                                         tmpphone[b]=buf[c];
249                                         tmpphone[b+1]=0;
250                                         }
251                                 }
252                         vcard_set_prop(my_vcard, "tel;home", tmpphone);
253                         }
254                 if (a==6) vcard_set_prop(my_vcard, "email;internet", buf);
255                 ++a;
256                 }
257         sprintf(tmpaddress, ";;%s;%s;%s;%s;USA",
258                 tmpaddr, tmpcity, tmpstate, tmpzip);
259         vcard_set_prop(my_vcard, "adr", tmpaddress);
260         vcard_write_user(&CC->usersupp, my_vcard);
261         vcard_free(my_vcard);
262
263         lgetuser(&CC->usersupp, CC->curr_user);
264         CC->usersupp.flags=(CC->usersupp.flags|US_REGIS|US_NEEDVALID);
265         lputuser(&CC->usersupp);
266
267         /* set global flag calling for validation */
268         begin_critical_section(S_CONTROL);
269         get_control();
270         CitControl.MMflags = CitControl.MMflags | MM_VALID ;
271         put_control();
272         end_critical_section(S_CONTROL);
273         }
274
275
276
277 /*
278  * get registration info for a user
279  */
280 void cmd_greg(char *argbuf)
281 {
282         struct usersupp usbuf;
283         struct vCard *v;
284         char *tel;
285         char who[256];
286         char adr[256];
287         char buf[256];
288
289         extract(who, argbuf, 0);
290
291         if (!(CC->logged_in)) {
292                 cprintf("%d Not logged in.\n", ERROR+NOT_LOGGED_IN);
293                 return;
294         }
295
296         if (!strcasecmp(who,"_SELF_")) strcpy(who,CC->curr_user);
297
298         if ((CC->usersupp.axlevel < 6) && (strcasecmp(who,CC->curr_user))) {
299                 cprintf("%d Higher access required.\n",
300                         ERROR+HIGHER_ACCESS_REQUIRED);
301                 return;
302         }
303
304         if (getuser(&usbuf, who) != 0) {
305                 cprintf("%d '%s' not found.\n", ERROR+NO_SUCH_USER, who);
306                 return;
307         }
308
309         v = vcard_get_user(&usbuf);
310
311         cprintf("%d %s\n", LISTING_FOLLOWS, usbuf.fullname);
312         cprintf("%ld\n", usbuf.usernum);
313         cprintf("%s\n", usbuf.password);
314         cprintf("%s\n", vcard_get_prop(v, "n", 0));     /* name */
315
316         sprintf(adr, "%s", vcard_get_prop(v, "adr", 0));/* address... */
317
318         extract_token(buf, adr, 2, ';');
319         cprintf("%s\n", buf);                           /* street */
320         extract_token(buf, adr, 3, ';');
321         cprintf("%s\n", buf);                           /* city */
322         extract_token(buf, adr, 4, ';');
323         cprintf("%s\n", buf);                           /* state */
324         extract_token(buf, adr, 5, ';');
325         cprintf("%s\n", buf);                           /* zip */
326
327         tel = vcard_get_prop(v, "tel;home", 0);
328         if (tel == NULL) tel = vcard_get_prop(v, "tel", 1);
329         if (tel != NULL) {
330                 cprintf("%s\n", tel);
331                 }
332         else {
333                 cprintf(" \n");
334         }
335
336         cprintf("%d\n", usbuf.axlevel);
337
338         cprintf("%s\n", vcard_get_prop(v, "email;internet", 0));
339         cprintf("000\n");
340         }
341
342
343
344 void vcard_session_startup_hook(void) {
345         CtdlAllocUserData(SYM_VCARD, sizeof(struct vcard_internal_info));
346 }
347
348
349
350 char *Dynamic_Module_Init(void)
351 {
352         SYM_VCARD = CtdlGetDynamicSymbol();
353         CtdlRegisterSessionHook(vcard_session_startup_hook, EVT_START);
354         CtdlRegisterMessageHook(vcard_personal_upload, EVT_BEFORESAVE);
355         CtdlRegisterProtoHook(cmd_regi, "REGI", "Enter registration info");
356         CtdlRegisterProtoHook(cmd_greg, "GREG", "Get registration info");
357         return "$Id$";
358 }