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