05cab0d453ac7e394e56cd17e3bf716e39c66cc8
[citadel.git] / webcit / useredit.c
1 /*
2  * Copyright (c) 1996-2021 by the citadel.org team
3  *
4  * This program is open source software.  You can redistribute it and/or
5  * modify it under the terms of the GNU General Public License, version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12
13 #include "webcit.h"
14 #include "webserver.h"
15
16 CtxType CTX_USERLIST = CTX_NONE;
17 /*
18  *  show a list of available users to edit them
19  *  message the header message???
20  *  preselect = which user should be selected in the browser
21  */
22 void select_user_to_edit(const char *preselect)
23 {
24         output_headers(1, 0, 0, 0, 1, 0);
25         do_template("aide_edituser_select");
26         end_burst();
27 }
28
29
30 typedef struct _UserListEntry {
31         int UID;
32         int AccessLevel;
33         int nLogons;
34         int nPosts;
35
36         StrBuf *UserName;
37         StrBuf *Passvoid;
38         time_t LastLogonT;
39         /* Just available for Single users to view: */
40         unsigned int Flags;
41         int DaysTillPurge;
42         int HasBio;
43
44         StrBuf *PrimaryEmail;
45         StrBuf *OtherEmails;
46
47 } UserListEntry;
48
49
50 UserListEntry* NewUserListOneEntry(StrBuf *SerializedUser, const char *Pos)
51 {
52         UserListEntry *ul;
53
54         if (StrLength(SerializedUser) < 8) 
55                 return NULL;
56
57         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
58         ul->UserName = NewStrBuf();
59         ul->Passvoid = NewStrBuf();
60         ul->PrimaryEmail = NewStrBuf();
61         ul->OtherEmails = NewStrBuf();
62
63         StrBufExtract_NextToken(ul->UserName,               SerializedUser, &Pos, '|');
64         StrBufExtract_NextToken(ul->Passvoid,               SerializedUser, &Pos, '|');
65         ul->Flags         = StrBufExtractNext_unsigned_long(SerializedUser, &Pos, '|');
66         ul->nLogons       = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
67         ul->nPosts        = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
68         ul->AccessLevel   = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
69         ul->UID           = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
70         ul->LastLogonT    = StrBufExtractNext_long(         SerializedUser, &Pos, '|');
71         ul->DaysTillPurge = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
72         return ul;
73 }
74
75 void DeleteUserListEntry(void *vUserList)
76 {
77         UserListEntry *ul = (UserListEntry*) vUserList;
78         if (!ul) return;
79         FreeStrBuf(&ul->UserName);
80         FreeStrBuf(&ul->Passvoid);
81         FreeStrBuf(&ul->PrimaryEmail);
82         FreeStrBuf(&ul->OtherEmails);
83         free(ul);
84 }
85
86 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
87 {
88         const char *Pos = NULL;
89         UserListEntry *ul;
90
91         if (StrLength(SerializedUserList) < 8) 
92                 return NULL;
93
94         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
95         ul->UserName = NewStrBuf();
96         ul->Passvoid = NewStrBuf();
97         ul->PrimaryEmail = NewStrBuf();
98         ul->OtherEmails = NewStrBuf();
99
100         StrBufExtract_NextToken(ul->UserName,    SerializedUserList, &Pos, '|');
101         ul->AccessLevel = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
102         ul->UID         = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
103         ul->LastLogonT  = StrBufExtractNext_long(SerializedUserList, &Pos, '|');
104         ul->nLogons     = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
105         ul->nPosts      = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
106         StrBufExtract_NextToken(ul->Passvoid,    SerializedUserList, &Pos, '|');
107         ul->Flags = 0;
108         ul->HasBio = 0;
109         ul->DaysTillPurge = -1;
110         return ul;
111 }
112
113 /*
114  * Sort by Username
115  */
116 int CompareUserListName(const void *vUser1, const void *vUser2)
117 {
118         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
119         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
120
121         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
122 }
123
124 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
125 {
126         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
127         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
128         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
129 }
130
131 int GroupchangeUserListName(const void *vUser1, const void *vUser2)
132 {
133         UserListEntry *u1 = (UserListEntry*) vUser1;
134         UserListEntry *u2 = (UserListEntry*) vUser2;
135         return ChrPtr(u2->UserName)[0] != ChrPtr(u1->UserName)[0];
136 }
137
138 /*
139  * Sort by access level
140  */
141 int CompareAccessLevel(const void *vUser1, const void *vUser2)
142 {
143         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
144         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
145
146         return (u1->AccessLevel > u2->AccessLevel);
147 }
148
149 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
150 {
151         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
152         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
153
154         return (u2->AccessLevel > u1->AccessLevel);
155 }
156
157 int GroupchangeAccessLevel(const void *vUser1, const void *vUser2)
158 {
159         UserListEntry *u1 = (UserListEntry*) vUser1;
160         UserListEntry *u2 = (UserListEntry*) vUser2;
161
162         return u2->AccessLevel != u1->AccessLevel;
163 }
164
165 /*
166  * Sort by UID
167  */
168 int CompareUID(const void *vUser1, const void *vUser2)
169 {
170         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
171         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
172
173         return (u1->UID > u2->UID);
174 }
175
176 int CompareUIDRev(const void *vUser1, const void *vUser2)
177 {
178         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
179         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
180
181         return (u2->UID > u1->UID);
182 }
183
184 int GroupchangeUID(const void *vUser1, const void *vUser2)
185 {
186         UserListEntry *u1 = (UserListEntry*) vUser1;
187         UserListEntry *u2 = (UserListEntry*) vUser2;
188
189         return (u2->UID / 10) != (u1->UID / 10);
190 }
191
192 /*
193  * Sort By Date /// TODO!
194  */
195 int CompareLastLogon(const void *vUser1, const void *vUser2)
196 {
197         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
198         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
199
200         return (u1->LastLogonT > u2->LastLogonT);
201 }
202
203 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
204 {
205         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
206         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
207
208         return (u2->LastLogonT > u1->LastLogonT);
209 }
210
211 int GroupchangeLastLogon(const void *vUser1, const void *vUser2)
212 {
213         UserListEntry *u1 = (UserListEntry*) vUser1;
214         UserListEntry *u2 = (UserListEntry*) vUser2;
215
216         return (u2->LastLogonT != u1->LastLogonT);
217 }
218
219 /*
220  * Sort By Number of Logons
221  */
222 int ComparenLogons(const void *vUser1, const void *vUser2)
223 {
224         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
225         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
226
227         return (u1->nLogons > u2->nLogons);
228 }
229
230 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
231 {
232         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
233         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
234
235         return (u2->nLogons > u1->nLogons);
236 }
237
238 int GroupchangenLogons(const void *vUser1, const void *vUser2)
239 {
240         UserListEntry *u1 = (UserListEntry*) vUser1;
241         UserListEntry *u2 = (UserListEntry*) vUser2;
242
243         return (u2->nLogons / 100) != (u1->nLogons / 100);
244 }
245
246 /*
247  * Sort By Number of Posts
248  */
249 int ComparenPosts(const void *vUser1, const void *vUser2)
250 {
251         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
252         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
253
254         return (u1->nPosts > u2->nPosts);
255 }
256
257 int ComparenPostsRev(const void *vUser1, const void *vUser2)
258 {
259         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
260         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
261
262         return (u2->nPosts > u1->nPosts);
263 }
264
265 int GroupchangenPosts(const void *vUser1, const void *vUser2)
266 {
267         UserListEntry *u1 = (UserListEntry*) vUser1;
268         UserListEntry *u2 = (UserListEntry*) vUser2;
269
270         return (u2->nPosts / 100) != (u1->nPosts / 100);
271 }
272
273
274 HashList *iterate_load_userlist(StrBuf *Target, WCTemplputParams *TP)
275 {
276         int Done = 0;
277         CompareFunc SortIt;
278         HashList *Hash = NULL;
279         StrBuf *Buf;
280         UserListEntry* ul;
281         int len;
282         int UID;
283         void *vData;
284         WCTemplputParams SubTP;
285
286         memset(&SubTP, 0, sizeof(WCTemplputParams));    
287         serv_puts("LIST");
288         Buf = NewStrBuf();
289         StrBuf_ServGetln(Buf);
290         if (GetServerStatus(Buf, NULL) == 1) {
291                 Hash = NewHash(1, Flathash);
292                 Done = 0;
293                 while (!Done) {
294                         len = StrBuf_ServGetln(Buf);
295                         if ((len <0) || 
296                             ((len == 3) &&
297                              !strcmp(ChrPtr(Buf), "000")))
298                         {
299                                 Done = 1;
300                                 break;
301                         }
302                         ul = NewUserListEntry(Buf);
303                         if (ul == NULL)
304                                 continue;
305
306                         Put(Hash, IKEY(ul->UID), ul, DeleteUserListEntry); 
307                 }
308
309                 serv_puts("LBIO 1");
310                 StrBuf_ServGetln(Buf);
311                 if (GetServerStatus(Buf, NULL) == 1) {
312                         Done = 0;
313                         while (!Done) {
314                                 len = StrBuf_ServGetln(Buf);
315                                 if ((len <0) || ((len == 3) && !strcmp(ChrPtr(Buf), "000")))
316                                 {
317                                         Done = 1;
318                                         break;
319                                 }
320                         }
321                         UID = atoi(ChrPtr(Buf));
322                         if (GetHash(Hash, IKEY(UID), &vData) && vData != 0)
323                         {
324                                 ul = (UserListEntry*)vData;
325                                 ul->HasBio = 1;
326                         }
327                 }
328                 SubTP.Filter.ContextType = CTX_USERLIST;
329                 SortIt = RetrieveSort(&SubTP, HKEY("USER"), HKEY("user:uid"), 0);
330                 if (SortIt != NULL)
331                         SortByPayload(Hash, SortIt);
332                 else 
333                         SortByPayload(Hash, CompareUID);
334         }
335         FreeStrBuf(&Buf);
336         return Hash;
337 }
338
339
340 void tmplput_USERLIST_UserName(StrBuf *Target, WCTemplputParams *TP)
341 {
342         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
343         StrBufAppendTemplate(Target, TP, ul->UserName, 0);
344 }
345
346 void tmplput_USERLIST_Password(StrBuf *Target, WCTemplputParams *TP)
347 {
348         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
349         StrBufAppendTemplate(Target, TP, ul->Passvoid, 0);
350 }
351
352 void tmplput_USERLIST_PrimaryEmail(StrBuf *Target, WCTemplputParams *TP)
353 {
354         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
355         StrBufAppendTemplate(Target, TP, ul->PrimaryEmail, 0);
356 }
357
358 void tmplput_USERLIST_OtherEmails(StrBuf *Target, WCTemplputParams *TP)
359 {
360         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
361         StrBufAppendTemplate(Target, TP, ul->OtherEmails, 0);
362 }
363
364 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, WCTemplputParams *TP)
365 {
366         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
367
368         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
369 }
370
371 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, WCTemplputParams *TP)
372 {
373         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
374         
375         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
376 }
377
378 void tmplput_USERLIST_UID(StrBuf *Target, WCTemplputParams *TP)
379 {
380         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
381
382         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
383 }
384
385
386 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, WCTemplputParams *TP)
387 {
388         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
389
390         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
391 }
392
393
394 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, WCTemplputParams *TP)
395 {
396         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
397         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
398 }
399
400
401 void tmplput_USERLIST_nLogons(StrBuf *Target, WCTemplputParams *TP)
402 {
403         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
404
405         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
406 }
407
408
409 void tmplput_USERLIST_nPosts(StrBuf *Target, WCTemplputParams *TP)
410 {
411         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
412
413         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
414 }
415
416
417 void tmplput_USERLIST_Flags(StrBuf *Target, WCTemplputParams *TP)
418 {
419         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
420
421         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
422 }
423
424
425 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, WCTemplputParams *TP)
426 {
427         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
428
429         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
430 }
431
432
433 int ConditionalUser(StrBuf *Target, WCTemplputParams *TP)
434 {
435         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
436         if (havebstr("usernum")) {
437                 return ibstr("usernum") == ul->UID;
438         }
439         else if (havebstr("username")) {
440                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
441         }
442         else 
443                 return 0;
444 }
445
446
447 int ConditionalFlagINetEmail(StrBuf *Target, WCTemplputParams *TP)
448 {
449         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
450         return (ul->Flags & US_INTERNET) != 0;
451 }
452
453
454 int ConditionalUserAccess(StrBuf *Target, WCTemplputParams *TP)
455 {
456         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
457         
458         if (ul == NULL)
459                 return 0;
460
461         return GetTemplateTokenNumber(Target, 
462                                       TP, 
463                                       3, 
464                                       AxNewU)
465                 ==
466                 ul->AccessLevel;
467 }
468
469
470 int ConditionalHaveBIO(StrBuf *Target, WCTemplputParams *TP)
471 {
472         UserListEntry *ul = (UserListEntry*) CTX(CTX_USERLIST);
473         
474         if (ul == NULL)
475                 return 0;
476         return ul->HasBio;
477 }
478
479
480 int ConditionalSuppressEmailFields(StrBuf *Target, WCTemplputParams *TP)
481 {
482         return 0;               // FIXME this makes all email fields display
483 }
484
485
486 void tmplput_USER_BIO(StrBuf *Target, WCTemplputParams *TP)
487 {
488         int Done = 0;
489         StrBuf *Buf;
490         const char *who;
491         long len;
492
493         GetTemplateTokenString(Target, TP, 0, &who, &len);
494         if (len == 0) {
495                 who = ChrPtr(WC->wc_fullname);
496         }
497
498         Buf = NewStrBuf();
499         serv_printf("RBIO %s", who);
500         StrBuf_ServGetln(Buf);
501         if (GetServerStatus(Buf, NULL) == 1) {
502                 StrBuf *BioBuf = NewStrBufPlain(NULL, SIZ);
503                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
504                         if ( (StrLength(Buf)==3) && 
505                              !strcmp(ChrPtr(Buf), "000")) 
506                                 Done = 1;
507                         else {
508                                 StrBufAppendBuf(BioBuf, Buf, 0);
509                                 StrBufAppendBufPlain(BioBuf, HKEY("\n"), 0);
510                         }
511                 }
512                 StrBufAppendTemplate(Target, TP, BioBuf, 1);
513                 FreeStrBuf(&BioBuf);
514         }
515         FreeStrBuf(&Buf);
516 }
517
518
519 int Conditional_USER_HAS_PIC(StrBuf *Target, WCTemplputParams *TP)
520 {
521         // ajc 2016apr10 this needs to be re-evaluated with the new protocol
522         return(0);
523 }
524
525
526 /*
527  *  Locate the message number of a user's vCard in the current room
528  *  Returns the message id of his vcard
529  */
530 long locate_user_vcard_in_this_room(message_summary **VCMsg, wc_mime_attachment **VCAtt)
531 {
532         HashPos *at;
533         HashPos *att;
534         const char *HashKey;
535         long HKLen;
536         void *vMsg;
537         message_summary *Msg;
538         wc_mime_attachment *Att;
539         StrBuf *Buf;
540         long vcard_msgnum = (-1L);
541         int already_tried_creating_one = 0;
542         StrBuf *FoundCharset = NewStrBuf();
543         StrBuf *Error = NULL;
544         SharedMessageStatus Stat;
545
546
547         Buf = NewStrBuf();
548 TRYAGAIN:
549         memset(&Stat, 0, sizeof(SharedMessageStatus));
550         Stat.maxload = 10000;
551         Stat.lowest_found = (-1);
552         Stat.highest_found = (-1);
553         /* Search for the user's vCard */
554         if (load_msg_ptrs("MSGS ALL||||1", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0) > 0) {
555                 at = GetNewHashPos(WC->summ, 0);
556                 while (GetNextHashPos(WC->summ, at, &HKLen, &HashKey, &vMsg)) {
557                         Msg = (message_summary*) vMsg;          
558                         Msg->MsgBody =  (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
559                         memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment));
560                         Msg->MsgBody->msgnum = Msg->msgnum;
561
562                         load_message(Msg, FoundCharset, &Error);
563                         
564                         if (Msg->AllAttach != NULL) {
565                                 att = GetNewHashPos(Msg->AllAttach, 0);
566                                 while (GetNextHashPos(Msg->AllAttach, att, &HKLen, &HashKey, &vMsg) && 
567                                        (vcard_msgnum == -1)) {
568                                         Att = (wc_mime_attachment*) vMsg;
569                                         if (
570                                                 (strcasecmp(ChrPtr(Att->ContentType), "text/x-vcard") == 0)
571                                                 || (strcasecmp(ChrPtr(Att->ContentType), "text/vcard") == 0)
572                                         ) {
573                                                 *VCAtt = Att;
574                                                 *VCMsg = Msg;
575                                                 vcard_msgnum = Msg->msgnum;
576                                                 if (Att->Data == NULL) {
577                                                         MimeLoadData(Att);
578                                                 }
579                                         }
580                                 }
581                                 DeleteHashPos(&att);
582                         }
583                         FreeStrBuf(&Error);     /* don't care... */
584                         
585                 }
586                 DeleteHashPos(&at);             
587         }
588
589         /* If there's no vcard, create one */
590         if ((*VCMsg == NULL) && (already_tried_creating_one == 0)) {
591                 FlushStrBuf(Buf);
592                 already_tried_creating_one = 1;
593                 serv_puts("ENT0 1|||4");
594                 StrBuf_ServGetln(Buf);
595                 if (GetServerStatus(Buf, NULL) == 4) {
596                         serv_puts("Content-type: text/x-vcard");
597                         serv_puts("");
598                         serv_puts("begin:vcard");
599                         serv_puts("end:vcard");
600                         serv_puts("000");
601                 }
602                 else 
603                         syslog(LOG_WARNING, "Error while creating user vcard: %s\n", ChrPtr(Buf));
604                 goto TRYAGAIN;
605         }
606         FreeStrBuf(&Buf);
607         FreeStrBuf(&FoundCharset);
608
609         return(vcard_msgnum);
610 }
611
612
613 /*
614  *  Display the form for editing a user's address book entry
615  *  username the name of the user
616  *  usernum the citadel-uid of the user
617  */
618 void display_edit_address_book_entry(const char *username, long usernum) {
619         message_summary *VCMsg = NULL;
620         wc_mime_attachment *VCAtt = NULL;
621         StrBuf *roomname;
622         StrBuf *Buf;
623         long vcard_msgnum = (-1L);
624
625         /* Locate the user's config room, creating it if necessary */
626         Buf = NewStrBuf();
627         roomname = NewStrBuf();
628         StrBufPrintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
629         serv_printf("GOTO %s||1", ChrPtr(roomname));
630         StrBuf_ServGetln(Buf);
631         if (GetServerStatus(Buf, NULL) != 2) {
632                 serv_printf("CRE8 1|%s|5|||1|", ChrPtr(roomname));
633                 StrBuf_ServGetln(Buf);
634                 GetServerStatus(Buf, NULL);
635                 serv_printf("GOTO %s||1", ChrPtr(roomname));
636                 StrBuf_ServGetln(Buf);
637                 if (GetServerStatusMsg(Buf, NULL, 1, 2) != 2) {
638                         select_user_to_edit(username);
639                         FreeStrBuf(&Buf);
640                         FreeStrBuf(&roomname);
641                         return;
642                 }
643         }
644         FreeStrBuf(&Buf);
645
646         locate_user_vcard_in_this_room(&VCMsg, &VCAtt);
647
648         if (VCMsg == NULL) {
649                 AppendImportantMessage(_("An error occurred while trying to create or edit this address book entry."), -1);
650                 select_user_to_edit(username);
651                 FreeStrBuf(&roomname);
652                 return;
653         }
654
655         do_edit_vcard(vcard_msgnum, "1", 
656                       VCMsg,
657                       VCAtt,
658                       "select_user_to_edit", 
659                       ChrPtr(roomname));
660         FreeStrBuf(&roomname);
661 }
662
663 /*
664  *  purge a user 
665  *  username the name of the user to remove
666  */
667 void delete_user(char *username) {
668         StrBuf *Buf;
669         
670         Buf = NewStrBuf();
671         serv_printf("ASUP %s|0|0|0|0|0|", username);
672         StrBuf_ServGetln(Buf);
673         GetServerStatusMsg(Buf, NULL, 1, 2);
674
675         select_user_to_edit( bstr("username"));
676         FreeStrBuf(&Buf);
677 }
678                 
679
680 void display_edituser(const char *supplied_username, int is_new) {
681         const char *Pos;
682         UserListEntry* UL;
683         StrBuf *Buf;
684         char username[256];
685         int i = 0;
686
687         if (supplied_username != NULL) {
688                 safestrncpy(username, supplied_username, sizeof username);
689         }
690         else {
691                 safestrncpy(username, bstr("username"), sizeof username);
692         }
693
694         Buf = NewStrBuf();
695         serv_printf("AGUP %s", username);
696         StrBuf_ServGetln(Buf);
697         if (GetServerStatusMsg(Buf, NULL, 1, 2) != 2) {
698                 select_user_to_edit(username);
699                 FreeStrBuf(&Buf);
700                 return;
701         }
702         else {
703                 Pos = ChrPtr(Buf) + 4;
704                 UL = NewUserListOneEntry(Buf, Pos);
705                 if ((UL != NULL) && havebstr("edit_abe_button")) {
706                         display_edit_address_book_entry(username, UL->UID);
707                 }
708                 else if ((UL != NULL) && havebstr("delete_button")) {
709                         delete_user(username);
710                 }
711                 else if (UL != NULL) {
712
713                         serv_printf("AGEA %s", username);
714                         StrBuf_ServGetln(Buf);
715                         if (GetServerStatusMsg(Buf, NULL, 1, 2) == 1) {
716                                 while(StrBuf_ServGetln(Buf) , strcmp(ChrPtr(Buf), "000")) {
717                                         if (i == 0) {
718                                                 StrBufAppendPrintf(UL->PrimaryEmail, "%s", ChrPtr(Buf));
719                                         }
720                                         if (i > 1) {
721                                                 StrBufAppendPrintf(UL->OtherEmails, ",");
722                                         }
723                                         if (i > 0) {
724                                                 StrBufAppendPrintf(UL->OtherEmails, "%s", ChrPtr(Buf));
725                                         }
726                                         ++i;
727                                 }
728                         }
729
730                         WCTemplputParams SubTP;
731                         memset(&SubTP, 0, sizeof(WCTemplputParams));
732                         SubTP.Filter.ContextType = CTX_USERLIST;
733                         SubTP.Context = UL;
734                         output_headers(1, 0, 0, 0, 1, 0);
735                         DoTemplate(HKEY("aide_edituser_detailview"), NULL, &SubTP);
736                         end_burst();
737                 }
738                 DeleteUserListEntry(UL);
739                 
740         }
741         FreeStrBuf(&Buf);
742 }
743
744 /*
745  *  do the backend operation of the user edit on the server
746  */
747 void edituser(void) {
748         int is_new = 0;
749         unsigned int flags = 0;
750         const char *username;
751
752         is_new = ibstr("is_new");
753         username = bstr("username");
754
755         if (!havebstr("ok_button")) {
756                 AppendImportantMessage(_("Changes were not saved."), -1);
757         }       
758         else {
759                 StrBuf *Buf = NewStrBuf();
760
761                 flags = ibstr("flags");
762                 if (yesbstr("inetmail")) {
763                         flags |= US_INTERNET;
764                 }
765                 else {
766                         flags &= ~US_INTERNET ;
767                 }
768
769                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
770                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
771                         StrBuf_ServGetln(Buf);
772                         if (GetServerStatusMsg(Buf, NULL, 1, 2) != 2) {
773                                 username = bstr("newname");
774                         }
775                 }
776
777                 /* Send the new account parameters */
778                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
779                         username,
780                         bstr("password"),
781                         flags,
782                         bstr("timescalled"),
783                         bstr("msgsposted"),
784                         bstr("axlevel"),
785                         bstr("usernum"),
786                         bstr("lastcall"),
787                         bstr("purgedays")
788                 );
789                 StrBuf_ServGetln(Buf);
790                 GetServerStatusMsg(Buf, NULL, 1, 2);
791
792                 /* Send the new email addresses.  First make up a delimited list... */
793                 char all_the_emails[512];
794                 snprintf(all_the_emails, sizeof all_the_emails, "%s,%s", bstr("primaryemail"), bstr("otheremails"));
795
796                 /* Replace any commas, semicolons, or spaces with newlines */
797                 char *pos;
798                 for (pos=all_the_emails; *pos!=0; ++pos) {
799                         if ((*pos == ',') || (*pos == ';') || (*pos == ' ')) *pos = '\n' ;
800                 }
801
802                 /* Remove any naughty inappropriate whitespace */
803                 string_trim(all_the_emails);
804                 while (pos = strstr(all_the_emails, "\n,"), (pos != NULL)) {
805                         strcpy(pos, pos+1);
806                 }
807                 while (pos = strstr(all_the_emails, ",\n"), (pos != NULL)) {
808                         strcpy(pos+1, pos+2);
809                 }
810                 while (pos = strstr(all_the_emails, "\n\n"), (pos != NULL)) {
811                         strcpy(pos+1, pos+2);
812                 }
813
814                 /* Now send it to the server. */
815                 serv_printf("ASEA %s", username);
816                 StrBuf_ServGetln(Buf);
817                 if (GetServerStatusMsg(Buf, NULL, 1, 2) == 4) {
818                         serv_printf("%s\n000", all_the_emails);
819                 }
820
821                 FreeStrBuf(&Buf);
822         }
823
824         /*
825          * If we are in the middle of creating a new user, move on to
826          * the vCard edit screen.
827          */
828         if (is_new) {
829                 display_edit_address_book_entry(username, lbstr("usernum") );
830         }
831         else {
832                 select_user_to_edit(username);
833         }
834 }
835
836
837 /*
838  * create a new user
839  * (take the web environment username and create it on the citadel server)
840  */
841 void create_user(void) {
842         long FullState;
843         StrBuf *Buf;
844         const char *username;
845
846         Buf = NewStrBuf();
847         username = bstr("username");
848         serv_printf("CREU %s", username);
849         StrBuf_ServGetln(Buf);
850         if (GetServerStatus(Buf, &FullState) == 2) {
851                 AppendImportantMessage(_("A new user has been created."), -1);
852                 display_edituser(username, 1);
853         }
854         else if (FullState == 570) {
855                 AppendImportantMessage(_("You are attempting to create a new user from within Citadel "
856                                          "while running in host based authentication mode.  In this mode, "
857                                          "you must create new users on the host system, not within Citadel."), 
858                                        -1);
859                 select_user_to_edit(NULL);
860         }
861         else {
862                 AppendImportantMessage(ChrPtr(Buf) + 4, StrLength(Buf) - 4);
863                 select_user_to_edit(NULL);
864         }
865         FreeStrBuf(&Buf);
866 }
867
868
869 void display_userpic(void) {
870         off_t bytes;
871         StrBuf *Buf = NewStrBuf();
872         const char *username = bstr("user");
873         serv_printf("DLUI %s", username);
874         StrBuf_ServGetln(Buf);
875         if (GetServerStatus(Buf, NULL) == 6) {
876                 StrBufCutLeft(Buf, 4);
877                 bytes = StrBufExtract_long(Buf, 0, '|');
878                 StrBuf *content_type = NewStrBuf();
879                 StrBufExtract_token(content_type, Buf, 3, '|');
880                 WC->WBuf = NewStrBuf();
881                 StrBuf_ServGetBLOBBuffered(WC->WBuf, bytes);
882                 http_transmit_thing(ChrPtr(content_type), 0);
883                 FreeStrBuf(&content_type);
884         }
885         else {
886                 output_error_pic("", "");
887         }
888         FreeStrBuf(&Buf);
889 }
890
891
892 void _select_user_to_edit(void) {
893         select_user_to_edit(NULL);
894 }
895
896
897 void _display_edituser(void) {
898         display_edituser(NULL, 0);
899 }
900
901
902 void 
903 InitModule_USEREDIT
904 (void)
905 {
906         RegisterCTX(CTX_USERLIST);
907         WebcitAddUrlHandler(HKEY("select_user_to_edit"), "", 0, _select_user_to_edit, 0);
908         WebcitAddUrlHandler(HKEY("display_edituser"), "", 0, _display_edituser, 0);
909         WebcitAddUrlHandler(HKEY("edituser"), "", 0, edituser, 0);
910         WebcitAddUrlHandler(HKEY("create_user"), "", 0, create_user, 0);
911         WebcitAddUrlHandler(HKEY("userpic"), "", 0, display_userpic, 0);
912
913         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, NULL, CTX_USERLIST);
914         RegisterNamespace("USERLIST:PASSWD",        0, 1, tmplput_USERLIST_Password, NULL, CTX_USERLIST);
915         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, NULL, CTX_USERLIST);
916         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, NULL, CTX_USERLIST);
917         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, NULL, CTX_USERLIST);
918         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, NULL, CTX_USERLIST);
919         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, NULL, CTX_USERLIST);
920         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, NULL, CTX_USERLIST);
921         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, NULL, CTX_USERLIST);
922         RegisterNamespace("USERLIST:PRIMARYEMAIL",  0, 1, tmplput_USERLIST_PrimaryEmail, NULL, CTX_USERLIST);
923         RegisterNamespace("USERLIST:OTHEREMAILS",   0, 1, tmplput_USERLIST_OtherEmails, NULL, CTX_USERLIST);
924         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, NULL, CTX_USERLIST);
925         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, NULL, CTX_USERLIST);
926
927         RegisterNamespace("USER:BIO", 1, 2, tmplput_USER_BIO,  NULL, CTX_NONE);
928
929         RegisterConditional("COND:USERNAME",                    0,      ConditionalUser,                CTX_USERLIST);
930         RegisterConditional("COND:USERACCESS",                  0,      ConditionalUserAccess,          CTX_USERLIST);
931         RegisterConditional("COND:USERLIST:FLAG:USE_INTERNET",  0,      ConditionalFlagINetEmail,       CTX_USERLIST);
932         RegisterConditional("COND:USERLIST:HAVEBIO",            0,      ConditionalHaveBIO,             CTX_USERLIST);
933         RegisterConditional("COND:USER:PIC",                    1,      Conditional_USER_HAS_PIC,       CTX_NONE);
934
935         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
936
937         RegisterSortFunc(HKEY("user:name"),
938                          HKEY("userlist"),
939                          CompareUserListName,
940                          CompareUserListNameRev,
941                          GroupchangeUserListName,
942                          CTX_USERLIST);
943         RegisterSortFunc(HKEY("user:accslvl"),
944                          HKEY("userlist"),
945                          CompareAccessLevel,
946                          CompareAccessLevelRev,
947                          GroupchangeAccessLevel,
948                          CTX_USERLIST);
949
950         RegisterSortFunc(HKEY("user:nlogons"),
951                          HKEY("userlist"),
952                          ComparenLogons,
953                          ComparenLogonsRev,
954                          GroupchangenLogons,
955                          CTX_USERLIST);
956
957         RegisterSortFunc(HKEY("user:uid"),
958                          HKEY("userlist"),
959                          CompareUID,
960                          CompareUIDRev,
961                          GroupchangeUID,
962                          CTX_USERLIST);
963
964         RegisterSortFunc(HKEY("user:lastlogon"),
965                          HKEY("userlist"),
966                          CompareLastLogon,
967                          CompareLastLogonRev,
968                          GroupchangeLastLogon,
969                          CTX_USERLIST);
970
971         RegisterSortFunc(HKEY("user:nmsgposts"),
972                          HKEY("userlist"),
973                          ComparenPosts,
974                          ComparenPostsRev,
975                          GroupchangenPosts,
976                          CTX_USERLIST);
977
978         REGISTERTokenParamDefine(AxDeleted);
979         REGISTERTokenParamDefine(AxNewU);
980         REGISTERTokenParamDefine(AxProbU);
981         REGISTERTokenParamDefine(AxLocU);
982         REGISTERTokenParamDefine(AxNetU);
983         REGISTERTokenParamDefine(AxPrefU);
984         REGISTERTokenParamDefine(AxAideU);
985 }
986