Removed the unused second argument from the do_template() macro
[citadel.git] / webcit / useredit.c
1 /*
2  * Copyright (c) 1996-2011 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 as
6  * published by the Free Software Foundation; either version 3 of the
7  * License, or (at your option) any later version.
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  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 } UserListEntry;
49
50
51 UserListEntry* NewUserListOneEntry(StrBuf *SerializedUser, const char *Pos)
52 {
53         UserListEntry *ul;
54
55         if (StrLength(SerializedUser) < 8) 
56                 return NULL;
57
58         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
59         ul->UserName = NewStrBuf();
60         ul->Passvoid = NewStrBuf();
61
62         StrBufExtract_NextToken(ul->UserName,               SerializedUser, &Pos, '|');
63         StrBufExtract_NextToken(ul->Passvoid,               SerializedUser, &Pos, '|');
64         ul->Flags         = StrBufExtractNext_unsigned_long(SerializedUser, &Pos, '|');
65         ul->nLogons       = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
66         ul->nPosts        = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
67         ul->AccessLevel   = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
68         ul->UID           = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
69         ul->LastLogonT    = StrBufExtractNext_long(         SerializedUser, &Pos, '|');
70         ul->DaysTillPurge = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
71         return ul;
72 }
73
74 void DeleteUserListEntry(void *vUserList)
75 {
76         UserListEntry *ul = (UserListEntry*) vUserList;
77         if (!ul) return;
78         FreeStrBuf(&ul->UserName);
79         FreeStrBuf(&ul->Passvoid);
80         free(ul);
81 }
82
83 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
84 {
85         const char *Pos = NULL;
86         UserListEntry *ul;
87
88         if (StrLength(SerializedUserList) < 8) 
89                 return NULL;
90
91         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
92         ul->UserName = NewStrBuf();
93         ul->Passvoid = NewStrBuf();
94
95         StrBufExtract_NextToken(ul->UserName,    SerializedUserList, &Pos, '|');
96         ul->AccessLevel = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
97         ul->UID         = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
98         ul->LastLogonT  = StrBufExtractNext_long(SerializedUserList, &Pos, '|');
99         ul->nLogons     = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
100         ul->nPosts      = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
101         StrBufExtract_NextToken(ul->Passvoid,    SerializedUserList, &Pos, '|');
102         ul->Flags = 0;
103         ul->DaysTillPurge = -1;
104         return ul;
105 }
106
107 /*
108  * Sort by Username
109  */
110 int CompareUserListName(const void *vUser1, const void *vUser2)
111 {
112         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
113         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
114
115         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
116 }
117
118 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
119 {
120         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
121         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
122         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
123 }
124
125 int GroupchangeUserListName(const void *vUser1, const void *vUser2)
126 {
127         UserListEntry *u1 = (UserListEntry*) vUser1;
128         UserListEntry *u2 = (UserListEntry*) vUser2;
129         return ChrPtr(u2->UserName)[0] != ChrPtr(u1->UserName)[0];
130 }
131
132 /*
133  * Sort by access level
134  */
135 int CompareAccessLevel(const void *vUser1, const void *vUser2)
136 {
137         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
138         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
139
140         return (u1->AccessLevel > u2->AccessLevel);
141 }
142
143 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
144 {
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 {
153         UserListEntry *u1 = (UserListEntry*) vUser1;
154         UserListEntry *u2 = (UserListEntry*) vUser2;
155
156         return u2->AccessLevel != u1->AccessLevel;
157 }
158
159 /*
160  * Sort by UID
161  */
162 int CompareUID(const void *vUser1, const void *vUser2)
163 {
164         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
165         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
166
167         return (u1->UID > u2->UID);
168 }
169
170 int CompareUIDRev(const void *vUser1, const void *vUser2)
171 {
172         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
173         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
174
175         return (u2->UID > u1->UID);
176 }
177
178 int GroupchangeUID(const void *vUser1, const void *vUser2)
179 {
180         UserListEntry *u1 = (UserListEntry*) vUser1;
181         UserListEntry *u2 = (UserListEntry*) vUser2;
182
183         return (u2->UID / 10) != (u1->UID / 10);
184 }
185
186 /*
187  * Sort By Date /// TODO!
188  */
189 int CompareLastLogon(const void *vUser1, const void *vUser2)
190 {
191         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
192         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
193
194         return (u1->LastLogonT > u2->LastLogonT);
195 }
196
197 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
198 {
199         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
200         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
201
202         return (u2->LastLogonT > u1->LastLogonT);
203 }
204
205 int GroupchangeLastLogon(const void *vUser1, const void *vUser2)
206 {
207         UserListEntry *u1 = (UserListEntry*) vUser1;
208         UserListEntry *u2 = (UserListEntry*) vUser2;
209
210         return (u2->LastLogonT != u1->LastLogonT);
211 }
212
213 /*
214  * Sort By Number of Logons
215  */
216 int ComparenLogons(const void *vUser1, const void *vUser2)
217 {
218         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
219         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
220
221         return (u1->nLogons > u2->nLogons);
222 }
223
224 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
225 {
226         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
227         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
228
229         return (u2->nLogons > u1->nLogons);
230 }
231
232 int GroupchangenLogons(const void *vUser1, const void *vUser2)
233 {
234         UserListEntry *u1 = (UserListEntry*) vUser1;
235         UserListEntry *u2 = (UserListEntry*) vUser2;
236
237         return (u2->nLogons / 100) != (u1->nLogons / 100);
238 }
239
240 /*
241  * Sort By Number of Posts
242  */
243 int ComparenPosts(const void *vUser1, const void *vUser2)
244 {
245         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
246         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
247
248         return (u1->nPosts > u2->nPosts);
249 }
250
251 int ComparenPostsRev(const void *vUser1, const void *vUser2)
252 {
253         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
254         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
255
256         return (u2->nPosts > u1->nPosts);
257 }
258
259 int GroupchangenPosts(const void *vUser1, const void *vUser2)
260 {
261         UserListEntry *u1 = (UserListEntry*) vUser1;
262         UserListEntry *u2 = (UserListEntry*) vUser2;
263
264         return (u2->nPosts / 100) != (u1->nPosts / 100);
265 }
266
267
268 HashList *iterate_load_userlist(StrBuf *Target, WCTemplputParams *TP)
269 {
270         int Done = 0;
271         CompareFunc SortIt;
272         HashList *Hash = NULL;
273         StrBuf *Buf;
274         UserListEntry* ul;
275         char nnn[64];
276         int nUsed;
277         int len;
278         WCTemplputParams SubTP;
279
280         memset(&SubTP, 0, sizeof(WCTemplputParams));    
281         serv_puts("LIST");
282         Buf = NewStrBuf();
283         StrBuf_ServGetln(Buf);
284         if (GetServerStatus(Buf, NULL) == 1) {
285                 Hash = NewHash(1, NULL);
286
287                 while (!Done) {
288                         len = StrBuf_ServGetln(Buf);
289                         if ((len <0) || 
290                             ((len == 3) &&
291                              !strcmp(ChrPtr(Buf), "000")))
292                         {
293                                 Done = 1;
294                                 break;
295                         }
296                         ul = NewUserListEntry(Buf);
297                         if (ul == NULL)
298                                 continue;
299                         nUsed = GetCount(Hash);
300                         nUsed = snprintf(nnn, sizeof(nnn), "%d", nUsed+1);
301                         Put(Hash, nnn, nUsed, ul, DeleteUserListEntry); 
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 {
317         UserListEntry *ul = (UserListEntry*) CTX;
318         StrBufAppendTemplate(Target, TP, ul->UserName, 0);
319 }
320
321 void tmplput_USERLIST_Password(StrBuf *Target, WCTemplputParams *TP)
322 {
323         UserListEntry *ul = (UserListEntry*) CTX;
324         StrBufAppendTemplate(Target, TP, ul->Passvoid, 0);
325 }
326
327 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, WCTemplputParams *TP)
328 {
329         UserListEntry *ul = (UserListEntry*) CTX;
330
331         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
332 }
333
334 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, WCTemplputParams *TP)
335 {
336         UserListEntry *ul = (UserListEntry*) CTX;
337         
338         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
339 }
340
341 void tmplput_USERLIST_UID(StrBuf *Target, WCTemplputParams *TP)
342 {
343         UserListEntry *ul = (UserListEntry*) CTX;
344
345         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
346 }
347
348 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, WCTemplputParams *TP)
349 {
350         UserListEntry *ul = (UserListEntry*) CTX;
351
352         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
353 }
354 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, WCTemplputParams *TP)
355 {
356         UserListEntry *ul = (UserListEntry*) CTX;
357         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
358 }
359
360 void tmplput_USERLIST_nLogons(StrBuf *Target, WCTemplputParams *TP)
361 {
362         UserListEntry *ul = (UserListEntry*) CTX;
363
364         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
365 }
366
367 void tmplput_USERLIST_nPosts(StrBuf *Target, WCTemplputParams *TP)
368 {
369         UserListEntry *ul = (UserListEntry*) CTX;
370
371         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
372 }
373
374 void tmplput_USERLIST_Flags(StrBuf *Target, WCTemplputParams *TP)
375 {
376         UserListEntry *ul = (UserListEntry*) CTX;
377
378         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
379 }
380
381 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, WCTemplputParams *TP)
382 {
383         UserListEntry *ul = (UserListEntry*) CTX;
384
385         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
386 }
387
388 int ConditionalUser(StrBuf *Target, WCTemplputParams *TP)
389 {
390         UserListEntry *ul = (UserListEntry*) CTX;
391         if (havebstr("usernum")) {
392                 return ibstr("usernum") == ul->UID;
393         }
394         else if (havebstr("username")) {
395                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
396         }
397         else 
398                 return 0;
399 }
400
401 int ConditionalFlagINetEmail(StrBuf *Target, WCTemplputParams *TP)
402 {
403         UserListEntry *ul = (UserListEntry*) CTX;
404         return (ul->Flags & US_INTERNET) != 0;
405 }
406
407 int ConditionalUserAccess(StrBuf *Target, WCTemplputParams *TP)
408 {
409         UserListEntry *ul = (UserListEntry*) CTX;
410         
411         if (ul == NULL)
412                 return 0;
413
414         return GetTemplateTokenNumber(Target, 
415                                       TP, 
416                                       3, 
417                                       AxNewU)
418                 ==
419                 ul->AccessLevel;
420 }
421
422 /*
423  *  Locate the message number of a user's vCard in the current room
424  *  Returns the message id of his vcard
425  */
426 long locate_user_vcard_in_this_room(message_summary **VCMsg, wc_mime_attachment **VCAtt)
427 {
428         wcsession *WCC = WC;
429         HashPos *at;
430         HashPos *att;
431         const char *HashKey;
432         long HKLen;
433         void *vMsg;
434         message_summary *Msg;
435         wc_mime_attachment *Att;
436         int Done;
437         StrBuf *Buf;
438         long vcard_msgnum = (-1L);
439         int already_tried_creating_one = 0;
440         StrBuf *FoundCharset = NewStrBuf();
441         StrBuf *Error = NULL;
442         SharedMessageStatus Stat;
443
444
445         Buf = NewStrBuf();
446 TRYAGAIN:
447         memset(&Stat, 0, sizeof(SharedMessageStatus));
448         Stat.maxload = 10000;
449         Stat.lowest_found = (-1);
450         Stat.highest_found = (-1);
451         Done = 0;
452         /* Search for the user's vCard */
453         if (load_msg_ptrs("MSGS ALL||||1", &Stat, NULL) > 0) {
454                 at = GetNewHashPos(WCC->summ, 0);
455                 while (GetNextHashPos(WCC->summ, at, &HKLen, &HashKey, &vMsg)) {
456                         Msg = (message_summary*) vMsg;          
457                         Msg->MsgBody =  (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
458                         memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment));
459                         Msg->MsgBody->msgnum = Msg->msgnum;
460
461                         load_message(Msg, FoundCharset, &Error);
462                         
463                         if (Msg->AllAttach != NULL) {
464                                 att = GetNewHashPos(Msg->AllAttach, 0);
465                                 while (GetNextHashPos(Msg->AllAttach, att, &HKLen, &HashKey, &vMsg) && 
466                                        (vcard_msgnum == -1)) {
467                                         Att = (wc_mime_attachment*) vMsg;
468                                         if (
469                                                 (strcasecmp(ChrPtr(Att->ContentType), "text/x-vcard") == 0)
470                                                 || (strcasecmp(ChrPtr(Att->ContentType), "text/vcard") == 0)
471                                         ) {
472                                                 *VCAtt = Att;
473                                                 *VCMsg = Msg;
474                                                 vcard_msgnum = Msg->msgnum;
475                                                 if (Att->Data == NULL) {
476                                                         MimeLoadData(Att);
477                                                 }
478                                         }
479                                 }
480                                 DeleteHashPos(&att);
481                         }
482                         FreeStrBuf(&Error);     /* don't care... */
483                         
484                 }
485                 DeleteHashPos(&at);             
486         }
487
488         /* If there's no vcard, create one */
489         if ((*VCMsg == NULL) && (already_tried_creating_one == 0)) {
490                 FlushStrBuf(Buf);
491                 already_tried_creating_one = 1;
492                 serv_puts("ENT0 1|||4");
493                 StrBuf_ServGetln(Buf);
494                 if (GetServerStatus(Buf, NULL) == 4) {
495                         serv_puts("Content-type: text/x-vcard");
496                         serv_puts("");
497                         serv_puts("begin:vcard");
498                         serv_puts("end:vcard");
499                         serv_puts("000");
500                 }
501                 else 
502                         syslog(1, "Error while creating user vcard: %s\n", ChrPtr(Buf));
503                 goto TRYAGAIN;
504         }
505         FreeStrBuf(&Buf);
506         FreeStrBuf(&FoundCharset);
507
508         return(vcard_msgnum);
509 }
510
511
512 /*
513  *  Display the form for editing a user's address book entry
514  *  username the name of the user
515  *  usernum the citadel-uid of the user
516  */
517 void display_edit_address_book_entry(const char *username, long usernum) {
518         wcsession *WCC = WC;
519         message_summary *VCMsg = NULL;
520         wc_mime_attachment *VCAtt = NULL;
521         StrBuf *roomname;
522         StrBuf *Buf;
523         long vcard_msgnum = (-1L);
524
525         /* Locate the user's config room, creating it if necessary */
526         Buf = NewStrBuf();
527         roomname = NewStrBuf();
528         StrBufPrintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
529         serv_printf("GOTO %s||1", ChrPtr(roomname));
530         StrBuf_ServGetln(Buf);
531         if (GetServerStatus(Buf, NULL) != 2) {
532                 serv_printf("CRE8 1|%s|5|||1|", ChrPtr(roomname));
533                 StrBuf_ServGetln(Buf);
534                 GetServerStatus(Buf, NULL);
535                 serv_printf("GOTO %s||1", ChrPtr(roomname));
536                 StrBuf_ServGetln(Buf);
537                 if (GetServerStatus(Buf, NULL) != 2) {
538                         FlushStrBuf(WCC->ImportantMsg);
539                         StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
540                         select_user_to_edit(username);
541                         FreeStrBuf(&Buf);
542                         FreeStrBuf(&roomname);
543                         return;
544                 }
545         }
546         FreeStrBuf(&Buf);
547
548         locate_user_vcard_in_this_room(&VCMsg, &VCAtt);
549
550         if (VCMsg == NULL) {
551                 StrBufPlain(WCC->ImportantMsg, 
552                             _("An error occurred while trying to create or edit this address book entry."), 
553                             0);
554                 select_user_to_edit(username);
555                 FreeStrBuf(&roomname);
556                 return;
557         }
558
559         do_edit_vcard(vcard_msgnum, "1", 
560                       VCMsg,
561                       VCAtt,
562                       "select_user_to_edit", 
563                       ChrPtr(roomname));
564         FreeStrBuf(&roomname);
565 }
566
567
568 void display_edituser(const char *supplied_username, int is_new) {
569         const char *Pos;
570         wcsession *WCC = WC;
571         UserListEntry* UL;
572         StrBuf *Buf;
573         char username[256];
574
575         if (supplied_username != NULL) {
576                 safestrncpy(username, supplied_username, sizeof username);
577         }
578         else {
579                 safestrncpy(username, bstr("username"), sizeof username);
580         }
581
582         Buf = NewStrBuf();
583         serv_printf("AGUP %s", username);
584         StrBuf_ServGetln(Buf);
585         if (GetServerStatus(Buf, NULL) != 2) {
586                 FlushStrBuf(WCC->ImportantMsg);
587                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
588                 select_user_to_edit(username);
589                 FreeStrBuf(&Buf);
590                 return;
591         }
592         else {
593                 Pos = ChrPtr(Buf) + 4;
594                 UL = NewUserListOneEntry(Buf, Pos);
595                 if ((UL != NULL) && havebstr("edit_abe_button")) {
596                         display_edit_address_book_entry(username, UL->UID);
597                 }
598                 else if ((UL != NULL) && havebstr("delete_button")) {
599                         delete_user(username);
600                 }
601                 else if (UL != NULL) {
602                         WCTemplputParams SubTP;
603                         memset(&SubTP, 0, sizeof(WCTemplputParams));
604                         SubTP.Filter.ContextType = CTX_USERLIST;
605                         SubTP.Context = UL;
606                         output_headers(1, 0, 0, 0, 1, 0);
607                         DoTemplate(HKEY("aide_edituser_detailview"), NULL, &SubTP);
608                         end_burst();
609                 }
610                 DeleteUserListEntry(UL);
611                 
612         }
613         FreeStrBuf(&Buf);
614 }
615
616 /*
617  *  do the backend operation of the user edit on the server
618  */
619 void edituser(void) {
620         wcsession *WCC = WC;
621         int is_new = 0;
622         unsigned int flags = 0;
623         const char *username;
624
625         is_new = ibstr("is_new");
626         username = bstr("username");
627
628         if (!havebstr("ok_button")) {
629                 StrBufPlain(WCC->ImportantMsg, _("Changes were not saved."), -1);
630         }       
631         else {
632                 StrBuf *Buf = NewStrBuf();
633
634                 flags = ibstr("flags");
635                 if (yesbstr("inetmail")) {
636                         flags |= US_INTERNET;
637                 }
638                 else {
639                         flags &= ~US_INTERNET ;
640                 }
641
642                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
643                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
644                         StrBuf_ServGetln(Buf);
645                         if (GetServerStatus(Buf, NULL) == 2) {
646                                 FlushStrBuf(WCC->ImportantMsg);
647                                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);                             
648                         }
649                         else {
650                                 username = bstr("newname");
651                         }
652                 }
653
654                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
655                         username,
656                         bstr("password"),
657                         flags,
658                         bstr("timescalled"),
659                         bstr("msgsposted"),
660                         bstr("axlevel"),
661                         bstr("usernum"),
662                         bstr("lastcall"),
663                         bstr("purgedays")
664                 );
665                 StrBuf_ServGetln(Buf);
666                 if (GetServerStatus(Buf, NULL) == 2) {
667                         StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
668                 }
669                 FreeStrBuf(&Buf);
670         }
671
672         /*
673          * If we are in the middle of creating a new user, move on to
674          * the vCard edit screen.
675          */
676         if (is_new) {
677                 display_edit_address_book_entry(username, lbstr("usernum") );
678         }
679         else {
680                 select_user_to_edit(username);
681         }
682 }
683
684 /*
685  *  burge a user 
686  *  username the name of the user to remove
687  */
688 void delete_user(char *username) {
689         wcsession *WCC = WC;
690         StrBuf *Buf;
691         
692         Buf = NewStrBuf();
693         serv_printf("ASUP %s|0|0|0|0|0|", username);
694         StrBuf_ServGetln(Buf);
695         if (GetServerStatus(Buf, NULL) != 2) 
696                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
697
698         select_user_to_edit( bstr("username"));
699         FreeStrBuf(&Buf);
700 }
701                 
702
703
704 /*
705  *  create a new user
706  * take the web environment username and create it on the citadel server
707  */
708 void create_user(void) {
709         wcsession *WCC = WC;
710         long FullState;
711         StrBuf *Buf;
712         const char *username;
713
714         Buf = NewStrBuf();
715         username = bstr("username");
716         serv_printf("CREU %s", username);
717         StrBuf_ServGetln(Buf);
718         if (GetServerStatus(Buf, &FullState) == 2) {
719                 sprintf(WC->ImportantMessage, _("A new user has been created."));
720                 display_edituser(username, 1);
721         }
722         else if (FullState == 570) {
723                 StrBufPlain(WCC->ImportantMsg, 
724                             _("You are attempting to create a new user from within Citadel "
725                               "while running in host based authentication mode.  In this mode, "
726                               "you must create new users on the host system, not within Citadel."), 
727                             0);
728                 select_user_to_edit(NULL);
729         }
730         else {
731                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
732                 select_user_to_edit(NULL);
733         }
734         FreeStrBuf(&Buf);
735 }
736
737
738 void _select_user_to_edit(void) {
739         select_user_to_edit(NULL);
740 }
741
742
743 void _display_edituser(void) {
744         display_edituser(NULL, 0);
745 }
746
747
748 void 
749 InitModule_USEREDIT
750 (void)
751 {
752         WebcitAddUrlHandler(HKEY("select_user_to_edit"), "", 0, _select_user_to_edit, 0);
753         WebcitAddUrlHandler(HKEY("display_edituser"), "", 0, _display_edituser, 0);
754         WebcitAddUrlHandler(HKEY("edituser"), "", 0, edituser, 0);
755         WebcitAddUrlHandler(HKEY("create_user"), "", 0, create_user, 0);
756
757         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, NULL, CTX_USERLIST);
758         RegisterNamespace("USERLIST:PASSWD",        0, 1, tmplput_USERLIST_Password, NULL, CTX_USERLIST);
759         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, NULL, CTX_USERLIST);
760         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, NULL, CTX_USERLIST);
761         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, NULL, CTX_USERLIST);
762         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, NULL, CTX_USERLIST);
763         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, NULL, CTX_USERLIST);
764         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, NULL, CTX_USERLIST);
765         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, NULL, CTX_USERLIST);
766                                                     
767         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, NULL, CTX_USERLIST);
768         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, NULL, CTX_USERLIST);
769
770         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
771         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
772         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
773
774         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
775         
776
777
778         RegisterSortFunc(HKEY("user:name"),
779                          HKEY("userlist"),
780                          CompareUserListName,
781                          CompareUserListNameRev,
782                          GroupchangeUserListName,
783                          CTX_USERLIST);
784         RegisterSortFunc(HKEY("user:accslvl"),
785                          HKEY("userlist"),
786                          CompareAccessLevel,
787                          CompareAccessLevelRev,
788                          GroupchangeAccessLevel,
789                          CTX_USERLIST);
790
791         RegisterSortFunc(HKEY("user:nlogons"),
792                          HKEY("userlist"),
793                          ComparenLogons,
794                          ComparenLogonsRev,
795                          GroupchangenLogons,
796                          CTX_USERLIST);
797
798         RegisterSortFunc(HKEY("user:uid"),
799                          HKEY("userlist"),
800                          CompareUID,
801                          CompareUIDRev,
802                          GroupchangeUID,
803                          CTX_USERLIST);
804
805         RegisterSortFunc(HKEY("user:lastlogon"),
806                          HKEY("userlist"),
807                          CompareLastLogon,
808                          CompareLastLogonRev,
809                          GroupchangeLastLogon,
810                          CTX_USERLIST);
811
812         RegisterSortFunc(HKEY("user:nmsgposts"),
813                          HKEY("userlist"),
814                          ComparenPosts,
815                          ComparenPostsRev,
816                          GroupchangenPosts,
817                          CTX_USERLIST);
818
819         REGISTERTokenParamDefine(AxDeleted);
820         REGISTERTokenParamDefine(AxNewU);
821         REGISTERTokenParamDefine(AxProbU);
822         REGISTERTokenParamDefine(AxLocU);
823         REGISTERTokenParamDefine(AxNetU);
824         REGISTERTokenParamDefine(AxPrefU);
825         REGISTERTokenParamDefine(AxAideU);
826 }
827