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