* Edit user: markup was showing through because USERLIST:PASSWD was not defined;...
[citadel.git] / webcit / useredit.c
1 /*
2  * $Id$
3  */
4
5 #include "webcit.h"
6 #include "webserver.h"
7
8
9 /**
10  *  show a list of available users to edit them
11  *  message the header message???
12  *  preselect which user should be selected in the browser
13  */
14 void select_user_to_edit(char *message, char *preselect)
15 {
16         output_headers(1, 0, 0, 0, 1, 0);
17         do_template("edituser_select", NULL);
18         end_burst();
19 }
20
21
22 typedef struct _UserListEntry {
23         int UID;
24         int AccessLevel;
25         int nLogons;
26         int nPosts;
27
28         StrBuf *UserName;
29         StrBuf *Passvoid;
30         time_t LastLogonT;
31         /* Just available for Single users to view: */
32         unsigned int Flags;
33         int DaysTillPurge;
34 } UserListEntry;
35
36
37 UserListEntry* NewUserListOneEntry(StrBuf *SerializedUser)
38 {
39         UserListEntry *ul;
40
41         if (StrLength(SerializedUser) < 8) 
42                 return NULL;
43
44         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
45         ul->UserName = NewStrBuf();
46         ul->Passvoid = NewStrBuf();
47
48         StrBufExtract_token(ul->UserName, SerializedUser, 0, '|');
49         StrBufExtract_token(ul->Passvoid, SerializedUser, 1, '|');
50         ul->Flags = (unsigned int)StrBufExtract_long(SerializedUser, 2, '|');
51         ul->nLogons = StrBufExtract_int(SerializedUser, 3, '|');
52         ul->nPosts = StrBufExtract_int(SerializedUser, 4, '|');
53         ul->AccessLevel = StrBufExtract_int(SerializedUser, 5, '|');
54         ul->UID = StrBufExtract_int(SerializedUser, 6, '|');
55         ul->LastLogonT = StrBufExtract_long(SerializedUser, 7, '|');
56         ul->DaysTillPurge = StrBufExtract_int(SerializedUser, 8, '|');
57         return ul;
58 }
59
60 void DeleteUserListEntry(void *vUserList)
61 {
62         UserListEntry *ul = (UserListEntry*) vUserList;
63         FreeStrBuf(&ul->UserName);
64         FreeStrBuf(&ul->Passvoid);
65         free(ul);
66 }
67
68 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
69 {
70         UserListEntry *ul;
71
72         if (StrLength(SerializedUserList) < 8) 
73                 return NULL;
74
75         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
76         ul->UserName = NewStrBuf();
77         ul->Passvoid = NewStrBuf();
78
79         StrBufExtract_token(ul->UserName, SerializedUserList, 0, '|');
80         ul->AccessLevel = StrBufExtract_int(SerializedUserList, 1, '|');
81         ul->UID = StrBufExtract_int(SerializedUserList, 2, '|');
82         ul->LastLogonT = StrBufExtract_long(SerializedUserList, 3, '|');
83         ul->nLogons = StrBufExtract_int(SerializedUserList, 4, '|');
84         ul->nPosts = StrBufExtract_int(SerializedUserList, 5, '|');
85         StrBufExtract_token(ul->Passvoid, SerializedUserList, 6, '|');
86         ul->Flags = 0;
87         ul->DaysTillPurge = -1;
88         return ul;
89 }
90
91 /*
92  * Sort by Username
93  */
94 int CompareUserListName(const void *vUser1, const void *vUser2)
95 {
96         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
97         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
98
99         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
100 }
101 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
102 {
103         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
104         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
105         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
106 }
107 int GroupchangeUserListName(const void *vUser1, const void *vUser2)
108 {
109         UserListEntry *u1 = (UserListEntry*) vUser1;
110         UserListEntry *u2 = (UserListEntry*) vUser2;
111         return ChrPtr(u2->UserName)[0] != ChrPtr(u1->UserName)[0];
112 }
113
114 /*
115  * Sort by AccessLevel
116  */
117 int CompareAccessLevel(const void *vUser1, const void *vUser2)
118 {
119         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
120         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
121
122         return (u1->AccessLevel > u2->AccessLevel);
123 }
124 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
125 {
126         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
127         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
128
129         return (u2->AccessLevel > u1->AccessLevel);
130 }
131 int GroupchangeAccessLevel(const void *vUser1, const void *vUser2)
132 {
133         UserListEntry *u1 = (UserListEntry*) vUser1;
134         UserListEntry *u2 = (UserListEntry*) vUser2;
135
136         return u2->AccessLevel != u1->AccessLevel;
137 }
138
139
140 /*
141  * Sort by UID
142  */
143 int CompareUID(const void *vUser1, const void *vUser2)
144 {
145         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
146         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
147
148         return (u1->UID > u2->UID);
149 }
150 int CompareUIDRev(const void *vUser1, const void *vUser2)
151 {
152         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
153         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
154
155         return (u2->UID > u1->UID);
156 }
157 int GroupchangeUID(const void *vUser1, const void *vUser2)
158 {
159         UserListEntry *u1 = (UserListEntry*) vUser1;
160         UserListEntry *u2 = (UserListEntry*) vUser2;
161
162         return (u2->UID / 10) != (u1->UID / 10);
163 }
164
165 /*
166  * Sort By Date /// TODO!
167  */
168 int CompareLastLogon(const void *vUser1, const void *vUser2)
169 {
170         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
171         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
172
173         return (u1->LastLogonT > u2->LastLogonT);
174 }
175 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
176 {
177         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
178         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
179
180         return (u2->LastLogonT > u1->LastLogonT);
181 }
182 int GroupchangeLastLogon(const void *vUser1, const void *vUser2)
183 {
184         UserListEntry *u1 = (UserListEntry*) vUser1;
185         UserListEntry *u2 = (UserListEntry*) vUser2;
186
187         return (u2->LastLogonT != u1->LastLogonT);
188 }
189
190 /*
191  * Sort By Number of Logons
192  */
193 int ComparenLogons(const void *vUser1, const void *vUser2)
194 {
195         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
196         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
197
198         return (u1->nLogons > u2->nLogons);
199 }
200 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
201 {
202         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
203         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
204
205         return (u2->nLogons > u1->nLogons);
206 }
207 int GroupchangenLogons(const void *vUser1, const void *vUser2)
208 {
209         UserListEntry *u1 = (UserListEntry*) vUser1;
210         UserListEntry *u2 = (UserListEntry*) vUser2;
211
212         return (u2->nLogons / 100) != (u1->nLogons / 100);
213 }
214
215 /*
216  * Sort By Number of Posts
217  */
218 int ComparenPosts(const void *vUser1, const void *vUser2)
219 {
220         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
221         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
222
223         return (u1->nPosts > u2->nPosts);
224 }
225 int ComparenPostsRev(const void *vUser1, const void *vUser2)
226 {
227         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
228         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
229
230         return (u2->nPosts > u1->nPosts);
231 }
232 int GroupchangenPosts(const void *vUser1, const void *vUser2)
233 {
234         UserListEntry *u1 = (UserListEntry*) vUser1;
235         UserListEntry *u2 = (UserListEntry*) vUser2;
236
237         return (u2->nPosts / 100) != (u1->nPosts / 100);
238 }
239
240
241 HashList *iterate_load_userlist(StrBuf *Target, WCTemplputParams *TP)
242 {
243         CompareFunc SortIt;
244         HashList *Hash;
245         char buf[SIZ];
246         StrBuf *Buf;
247         UserListEntry* ul;
248         char nnn[64];
249         int nUsed;
250         int len;
251         WCTemplputParams SubTP;
252
253         memset(&SubTP, 0, sizeof(WCTemplputParams));    
254         serv_puts("LIST");
255         serv_getln(buf, sizeof buf);
256         if (buf[0] == '1') {
257                 Hash = NewHash(1, NULL);
258
259                 Buf = NewStrBuf();
260                 while ((len = StrBuf_ServGetln(Buf),
261                         strcmp(ChrPtr(Buf), "000"))) {
262                         ul = NewUserListEntry(Buf);
263                         if (ul == NULL)
264                                 continue;
265                         nUsed = GetCount(Hash);
266                         nUsed = snprintf(nnn, sizeof(nnn), "%d", nUsed+1);
267                         Put(Hash, nnn, nUsed, ul, DeleteUserListEntry); 
268                 }
269                 FreeStrBuf(&Buf);
270                 SubTP.Filter.ContextType = CTX_USERLIST;
271                 SortIt = RetrieveSort(&SubTP, HKEY("USER"), HKEY("user:uid"), 0);
272                 if (SortIt != NULL)
273                         SortByPayload(Hash, SortIt);
274                 else 
275                         SortByPayload(Hash, CompareUID);
276                 return Hash;
277         }
278         return NULL;
279 }
280
281
282 void tmplput_USERLIST_UserName(StrBuf *Target, WCTemplputParams *TP)
283 {
284         UserListEntry *ul = (UserListEntry*) CTX;
285         StrBufAppendTemplate(Target, TP, ul->UserName, 0);
286 }
287
288 void tmplput_USERLIST_Password(StrBuf *Target, WCTemplputParams *TP)
289 {
290         UserListEntry *ul = (UserListEntry*) CTX;
291         StrBufAppendTemplate(Target, TP, ul->Passvoid, 0);
292 }
293
294 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, WCTemplputParams *TP)
295 {
296         UserListEntry *ul = (UserListEntry*) CTX;
297
298         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
299 }
300
301 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, WCTemplputParams *TP)
302 {
303         UserListEntry *ul = (UserListEntry*) CTX;
304         
305         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
306 }
307
308 void tmplput_USERLIST_UID(StrBuf *Target, WCTemplputParams *TP)
309 {
310         UserListEntry *ul = (UserListEntry*) CTX;
311
312         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
313 }
314
315 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, WCTemplputParams *TP)
316 {
317         UserListEntry *ul = (UserListEntry*) CTX;
318
319         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
320 }
321 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, WCTemplputParams *TP)
322 {
323         UserListEntry *ul = (UserListEntry*) CTX;
324         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
325 }
326
327 void tmplput_USERLIST_nLogons(StrBuf *Target, WCTemplputParams *TP)
328 {
329         UserListEntry *ul = (UserListEntry*) CTX;
330
331         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
332 }
333
334 void tmplput_USERLIST_nPosts(StrBuf *Target, WCTemplputParams *TP)
335 {
336         UserListEntry *ul = (UserListEntry*) CTX;
337
338         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
339 }
340
341 void tmplput_USERLIST_Flags(StrBuf *Target, WCTemplputParams *TP)
342 {
343         UserListEntry *ul = (UserListEntry*) CTX;
344
345         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
346 }
347
348 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, WCTemplputParams *TP)
349 {
350         UserListEntry *ul = (UserListEntry*) CTX;
351
352         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
353 }
354
355 int ConditionalUser(StrBuf *Target, WCTemplputParams *TP)
356 {
357         UserListEntry *ul = (UserListEntry*) CTX;
358         if (havebstr("usernum")) {
359                 return ibstr("usernum") == ul->UID;
360         }
361         else if (havebstr("username")) {
362                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
363         }
364         else 
365                 return 0;
366 }
367
368 int ConditionalFlagINetEmail(StrBuf *Target, WCTemplputParams *TP)
369 {
370         UserListEntry *ul = (UserListEntry*) CTX;
371         return (ul->Flags & US_INTERNET) != 0;
372 }
373
374 int ConditionalUserAccess(StrBuf *Target, WCTemplputParams *TP)
375 {
376         UserListEntry *ul = (UserListEntry*) CTX;
377
378         if (TP->Tokens->Params[3]->Type == TYPE_LONG)
379                 return (TP->Tokens->Params[3]->lvalue == ul->AccessLevel);
380         else
381                 return 0;
382 }
383
384 /*
385  *  Locate the message number of a user's vCard in the current room
386  *  Returns the message id of his vcard
387  */
388 long locate_user_vcard_in_this_room() {
389         char buf[SIZ];
390         long vcard_msgnum = (-1L);
391         char content_type[SIZ];
392         char partnum[SIZ];
393         int already_tried_creating_one = 0;
394
395         struct stuff_t {
396                 struct stuff_t *next;
397                 long msgnum;
398         };
399
400         struct stuff_t *stuff = NULL;
401         struct stuff_t *ptr;
402
403 TRYAGAIN:
404         /** Search for the user's vCard */
405         serv_puts("MSGS ALL");
406         serv_getln(buf, sizeof buf);
407         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
408                 ptr = malloc(sizeof(struct stuff_t));
409                 ptr->msgnum = atol(buf);
410                 ptr->next = stuff;
411                 stuff = ptr;
412         }
413
414         /** Iterate through the message list looking for vCards */
415         while (stuff != NULL) {
416                 serv_printf("MSG0 %ld|2", stuff->msgnum);
417                 serv_getln(buf, sizeof buf);
418                 if (buf[0]=='1') {
419                         while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
420                                 if (!strncasecmp(buf, "part=", 5)) {
421                                         extract_token(partnum, &buf[5], 2, '|', sizeof partnum);
422                                         extract_token(content_type, &buf[5], 4, '|', sizeof content_type);
423                                         if (  (!strcasecmp(content_type, "text/x-vcard"))
424                                            || (!strcasecmp(content_type, "text/vcard")) ) {
425                                                 vcard_msgnum = stuff->msgnum;
426                                         }
427                                 }
428                         }
429                 }
430
431                 ptr = stuff->next;
432                 free(stuff);
433                 stuff = ptr;
434         }
435
436         /** If there's no vcard, create one */
437         if ((vcard_msgnum < 0) && (already_tried_creating_one == 0)) {
438                 already_tried_creating_one = 1;
439                 serv_puts("ENT0 1|||4");
440                 serv_getln(buf, sizeof buf);
441                 if (buf[0] == '4') {
442                         serv_puts("Content-type: text/x-vcard");
443                         serv_puts("");
444                         serv_puts("begin:vcard");
445                         serv_puts("end:vcard");
446                         serv_puts("000");
447                 }
448                 goto TRYAGAIN;
449         }
450
451         return(vcard_msgnum);
452 }
453
454
455 /**
456  *  Display the form for editing a user's address book entry
457  *  username the name of the user
458  *  usernum the citadel-uid of the user
459  */
460 void display_edit_address_book_entry(char *username, long usernum) {
461         char roomname[SIZ];
462         char buf[SIZ];
463         char error_message[SIZ];
464         long vcard_msgnum = (-1L);
465
466         /** Locate the user's config room, creating it if necessary */
467         sprintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
468         serv_printf("GOTO %s||1", roomname);
469         serv_getln(buf, sizeof buf);
470         if (buf[0] != '2') {
471                 serv_printf("CRE8 1|%s|5|||1|", roomname);
472                 serv_getln(buf, sizeof buf);
473                 serv_printf("GOTO %s||1", roomname);
474                 serv_getln(buf, sizeof buf);
475                 if (buf[0] != '2') {
476                         sprintf(error_message,
477                                 "<img src=\"static/error.gif\" align=center>"
478                                 "%s<br /><br />\n", &buf[4]);
479                         select_user_to_edit(error_message, username);
480                         return;
481                 }
482         }
483
484         vcard_msgnum = locate_user_vcard_in_this_room();
485
486         if (vcard_msgnum < 0) {
487                 sprintf(error_message,
488                         "<img src=\"static/error.gif\" align=center>%s<br /><br />\n",
489                         _("An error occurred while trying to create or edit this address book entry.")
490                 );
491                 select_user_to_edit(error_message, username);
492                 return;
493         }
494
495         do_edit_vcard(vcard_msgnum, "1", "select_user_to_edit", roomname);
496 }
497
498
499 void display_edituser(char *supplied_username, int is_new) {
500         UserListEntry* UL;
501         StrBuf *Buf;
502         char error_message[1024];
503         char MajorStatus;
504         char username[256];
505
506         if (supplied_username != NULL) {
507                 safestrncpy(username, supplied_username, sizeof username);
508         }
509         else {
510                 safestrncpy(username, bstr("username"), sizeof username);
511         }
512
513         Buf = NewStrBuf();
514         serv_printf("AGUP %s", username);
515         StrBuf_ServGetln(Buf);
516         MajorStatus = ChrPtr(Buf)[0];
517         StrBufCutLeft(Buf, 4);
518         if (MajorStatus != '2') {
519                 /*TODO ImportantMessage */
520                 sprintf(error_message,
521                         "<img src=\"static/error.gif\" align=center>"
522                         "%s<br /><br />\n", ChrPtr(Buf));
523                 select_user_to_edit(error_message, username);
524                 FreeStrBuf(&Buf);
525                 return;
526         }
527         else {
528                 UL = NewUserListOneEntry(Buf);
529                 if (havebstr("edit_abe_button")) {
530                         display_edit_address_book_entry(username, UL->UID);
531                 }
532                 else if (havebstr("delete_button")) {
533                         delete_user(username);
534                 }
535                 else {
536                         WCTemplputParams SubTP;
537                         memset(&SubTP, 0, sizeof(WCTemplputParams));
538                         SubTP.Filter.ContextType = CTX_USERLIST;
539                         SubTP.Context = UL;
540                         output_headers(1, 0, 0, 0, 1, 0);
541                         DoTemplate(HKEY("userlist_detailview"), NULL, &SubTP);
542                         end_burst();
543                 }
544                 DeleteUserListEntry(UL);
545                 
546         }
547         FreeStrBuf(&Buf);
548 }
549
550 /**
551  *  do the backend operation of the user edit on the server
552  */
553 void edituser(void) {
554         char message[SIZ];
555         char buf[SIZ];
556         int is_new = 0;
557         unsigned int flags = 0;
558         char *username;
559
560         is_new = ibstr("is_new");
561         safestrncpy(message, "", sizeof message);
562         username = bstr("username");
563
564         if (!havebstr("ok_button")) {
565                 safestrncpy(message, _("Changes were not saved."), sizeof message);
566         }
567         
568         else {
569                 flags = ibstr("flags");
570                 if (yesbstr("inetmail")) {
571                         flags |= US_INTERNET;
572                 }
573                 else {
574                         flags &= ~US_INTERNET ;
575                 }
576
577                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
578                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
579                         serv_getln(buf, sizeof buf);
580                         if (buf[0] != '2') {
581                                 sprintf(&message[strlen(message)],
582                                         "<img src=\"static/error.gif\" align=center>"
583                                         "%s<br /><br />\n", &buf[4]);
584                         }
585                         else {
586                                 username = bstr("newname");
587                         }
588                 }
589
590                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
591                         username,
592                         bstr("password"),
593                         flags,
594                         bstr("timescalled"),
595                         bstr("msgsposted"),
596                         bstr("axlevel"),
597                         bstr("usernum"),
598                         bstr("lastcall"),
599                         bstr("purgedays")
600                 );
601                 serv_getln(buf, sizeof buf);
602                 if (buf[0] != '2') {
603                         sprintf(&message[strlen(message)],
604                                 "<img src=\"static/error.gif\" align=center>"
605                                 "%s<br /><br />\n", &buf[4]);
606                 }
607         }
608
609         /**
610          * If we are in the middle of creating a new user, move on to
611          * the vCard edit screen.
612          */
613         if (is_new) {
614                 display_edit_address_book_entry(username, lbstr("usernum") );
615         }
616         else {
617                 select_user_to_edit(message, username);
618         }
619 }
620
621 /*
622  *  burge a user 
623  *  username the name of the user to remove
624  */
625 void delete_user(char *username) {
626         char buf[SIZ];
627         char message[SIZ];
628
629         serv_printf("ASUP %s|0|0|0|0|0|", username);
630         serv_getln(buf, sizeof buf);
631         if (buf[0] != '2') {
632                 sprintf(message,
633                         "<img src=\"static/error.gif\" align=center>"
634                         "%s<br /><br />\n", &buf[4]);
635         }
636         else {
637                 safestrncpy(message, "", sizeof message);
638         }
639         select_user_to_edit(message, bstr("username"));
640 }
641                 
642
643
644 /**
645  *  create a new user
646  * take the web environment username and create it on the citadel server
647  */
648 void create_user(void) {
649         char buf[SIZ];
650         char error_message[SIZ];
651         char username[SIZ];
652
653         safestrncpy(username, bstr("username"), sizeof username);
654
655         serv_printf("CREU %s", username);
656         serv_getln(buf, sizeof buf);
657
658         if (buf[0] == '2') {
659                 sprintf(WC->ImportantMessage, _("A new user has been created."));
660                 display_edituser(username, 1);
661         }
662         else if (!strncmp(buf, "570", 3)) {
663                 sprintf(error_message,
664                         "<img src=\"static/error.gif\" align=center>"
665                         "%s<br /><br />\n",
666                         _("You are attempting to create a new user from within Citadel "
667                         "while running in host based authentication mode.  In this mode, "
668                         "you must create new users on the host system, not within Citadel.")
669                 );
670                 select_user_to_edit(error_message, NULL);
671         }
672         else {
673                 sprintf(error_message,
674                         "<img src=\"static/error.gif\" align=center>"
675                         "%s<br /><br />\n", &buf[4]);
676                 select_user_to_edit(error_message, NULL);
677         }
678
679 }
680
681
682 void _select_user_to_edit(void){select_user_to_edit(NULL, NULL);}
683 void _display_edituser(void) {display_edituser(NULL, 0);}
684
685 void 
686 InitModule_USEREDIT
687 (void)
688 {
689         WebcitAddUrlHandler(HKEY("select_user_to_edit"), _select_user_to_edit, 0);
690         WebcitAddUrlHandler(HKEY("display_edituser"), _display_edituser, 0);
691         WebcitAddUrlHandler(HKEY("edituser"), edituser, 0);
692         WebcitAddUrlHandler(HKEY("create_user"), create_user, 0);
693
694         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, CTX_USERLIST);
695         RegisterNamespace("USERLIST:PASSWD",        0, 1, tmplput_USERLIST_Password, CTX_USERLIST);
696         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, CTX_USERLIST);
697         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, CTX_USERLIST);
698         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, CTX_USERLIST);
699         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, CTX_USERLIST);
700         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, CTX_USERLIST);
701         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, CTX_USERLIST);
702         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, CTX_USERLIST);
703                                                     
704         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, CTX_USERLIST);
705         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, CTX_USERLIST);
706
707         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
708         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
709         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
710
711         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_NOFLAG);
712
713
714         RegisterSortFunc(HKEY("user:name"),
715                          HKEY("userlist"),
716                          CompareUserListName,
717                          CompareUserListNameRev,
718                          GroupchangeUserListName,
719                          CTX_USERLIST);
720         RegisterSortFunc(HKEY("user:accslvl"),
721                          HKEY("userlist"),
722                          CompareAccessLevel,
723                          CompareAccessLevelRev,
724                          GroupchangeAccessLevel,
725                          CTX_USERLIST);
726
727         RegisterSortFunc(HKEY("user:nlogons"),
728                          HKEY("userlist"),
729                          ComparenLogons,
730                          ComparenLogonsRev,
731                          GroupchangenLogons,
732                          CTX_USERLIST);
733
734         RegisterSortFunc(HKEY("user:uid"),
735                          HKEY("userlist"),
736                          CompareUID,
737                          CompareUIDRev,
738                          GroupchangeUID,
739                          CTX_USERLIST);
740
741         RegisterSortFunc(HKEY("user:lastlogon"),
742                          HKEY("userlist"),
743                          CompareLastLogon,
744                          CompareLastLogonRev,
745                          GroupchangeLastLogon,
746                          CTX_USERLIST);
747
748         RegisterSortFunc(HKEY("user:nmsgposts"),
749                          HKEY("userlist"),
750                          ComparenPosts,
751                          ComparenPostsRev,
752                          GroupchangenPosts,
753                          CTX_USERLIST);
754
755 }