* iterate_load_userlist() zeroed out the wrong struct; fixed
[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_AccessLevelNo(StrBuf *Target, WCTemplputParams *TP)
289 {
290         UserListEntry *ul = (UserListEntry*) CTX;
291
292         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
293 }
294
295 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, WCTemplputParams *TP)
296 {
297         UserListEntry *ul = (UserListEntry*) CTX;
298         
299         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
300 }
301
302 void tmplput_USERLIST_UID(StrBuf *Target, WCTemplputParams *TP)
303 {
304         UserListEntry *ul = (UserListEntry*) CTX;
305
306         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
307 }
308
309 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, WCTemplputParams *TP)
310 {
311         UserListEntry *ul = (UserListEntry*) CTX;
312
313         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
314 }
315 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, WCTemplputParams *TP)
316 {
317         UserListEntry *ul = (UserListEntry*) CTX;
318         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
319 }
320
321 void tmplput_USERLIST_nLogons(StrBuf *Target, WCTemplputParams *TP)
322 {
323         UserListEntry *ul = (UserListEntry*) CTX;
324
325         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
326 }
327
328 void tmplput_USERLIST_nPosts(StrBuf *Target, WCTemplputParams *TP)
329 {
330         UserListEntry *ul = (UserListEntry*) CTX;
331
332         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
333 }
334
335 void tmplput_USERLIST_Flags(StrBuf *Target, WCTemplputParams *TP)
336 {
337         UserListEntry *ul = (UserListEntry*) CTX;
338
339         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
340 }
341
342 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, WCTemplputParams *TP)
343 {
344         UserListEntry *ul = (UserListEntry*) CTX;
345
346         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
347 }
348
349 int ConditionalUser(StrBuf *Target, WCTemplputParams *TP)
350 {
351         UserListEntry *ul = (UserListEntry*) CTX;
352         if (havebstr("usernum")) {
353                 return ibstr("usernum") == ul->UID;
354         }
355         else if (havebstr("username")) {
356                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
357         }
358         else 
359                 return 0;
360 }
361
362 int ConditionalFlagINetEmail(StrBuf *Target, WCTemplputParams *TP)
363 {
364         UserListEntry *ul = (UserListEntry*) CTX;
365         return (ul->Flags & US_INTERNET) != 0;
366 }
367
368 int ConditionalUserAccess(StrBuf *Target, WCTemplputParams *TP)
369 {
370         UserListEntry *ul = (UserListEntry*) CTX;
371
372         if (TP->Tokens->Params[3]->Type == TYPE_LONG)
373                 return (TP->Tokens->Params[3]->lvalue == ul->AccessLevel);
374         else
375                 return 0;
376 }
377
378 /*
379  *  Locate the message number of a user's vCard in the current room
380  *  Returns the message id of his vcard
381  */
382 long locate_user_vcard_in_this_room() {
383         char buf[SIZ];
384         long vcard_msgnum = (-1L);
385         char content_type[SIZ];
386         char partnum[SIZ];
387         int already_tried_creating_one = 0;
388
389         struct stuff_t {
390                 struct stuff_t *next;
391                 long msgnum;
392         };
393
394         struct stuff_t *stuff = NULL;
395         struct stuff_t *ptr;
396
397 TRYAGAIN:
398         /** Search for the user's vCard */
399         serv_puts("MSGS ALL");
400         serv_getln(buf, sizeof buf);
401         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
402                 ptr = malloc(sizeof(struct stuff_t));
403                 ptr->msgnum = atol(buf);
404                 ptr->next = stuff;
405                 stuff = ptr;
406         }
407
408         /** Iterate through the message list looking for vCards */
409         while (stuff != NULL) {
410                 serv_printf("MSG0 %ld|2", stuff->msgnum);
411                 serv_getln(buf, sizeof buf);
412                 if (buf[0]=='1') {
413                         while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
414                                 if (!strncasecmp(buf, "part=", 5)) {
415                                         extract_token(partnum, &buf[5], 2, '|', sizeof partnum);
416                                         extract_token(content_type, &buf[5], 4, '|', sizeof content_type);
417                                         if (  (!strcasecmp(content_type, "text/x-vcard"))
418                                            || (!strcasecmp(content_type, "text/vcard")) ) {
419                                                 vcard_msgnum = stuff->msgnum;
420                                         }
421                                 }
422                         }
423                 }
424
425                 ptr = stuff->next;
426                 free(stuff);
427                 stuff = ptr;
428         }
429
430         /** If there's no vcard, create one */
431         if ((vcard_msgnum < 0) && (already_tried_creating_one == 0)) {
432                 already_tried_creating_one = 1;
433                 serv_puts("ENT0 1|||4");
434                 serv_getln(buf, sizeof buf);
435                 if (buf[0] == '4') {
436                         serv_puts("Content-type: text/x-vcard");
437                         serv_puts("");
438                         serv_puts("begin:vcard");
439                         serv_puts("end:vcard");
440                         serv_puts("000");
441                 }
442                 goto TRYAGAIN;
443         }
444
445         return(vcard_msgnum);
446 }
447
448
449 /**
450  *  Display the form for editing a user's address book entry
451  *  username the name of the user
452  *  usernum the citadel-uid of the user
453  */
454 void display_edit_address_book_entry(char *username, long usernum) {
455         char roomname[SIZ];
456         char buf[SIZ];
457         char error_message[SIZ];
458         long vcard_msgnum = (-1L);
459
460         /** Locate the user's config room, creating it if necessary */
461         sprintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
462         serv_printf("GOTO %s||1", roomname);
463         serv_getln(buf, sizeof buf);
464         if (buf[0] != '2') {
465                 serv_printf("CRE8 1|%s|5|||1|", roomname);
466                 serv_getln(buf, sizeof buf);
467                 serv_printf("GOTO %s||1", roomname);
468                 serv_getln(buf, sizeof buf);
469                 if (buf[0] != '2') {
470                         sprintf(error_message,
471                                 "<img src=\"static/error.gif\" align=center>"
472                                 "%s<br /><br />\n", &buf[4]);
473                         select_user_to_edit(error_message, username);
474                         return;
475                 }
476         }
477
478         vcard_msgnum = locate_user_vcard_in_this_room();
479
480         if (vcard_msgnum < 0) {
481                 sprintf(error_message,
482                         "<img src=\"static/error.gif\" align=center>%s<br /><br />\n",
483                         _("An error occurred while trying to create or edit this address book entry.")
484                 );
485                 select_user_to_edit(error_message, username);
486                 return;
487         }
488
489         do_edit_vcard(vcard_msgnum, "1", "select_user_to_edit", roomname);
490 }
491
492
493 void display_edituser(char *supplied_username, int is_new) {
494         UserListEntry* UL;
495         StrBuf *Buf;
496         char error_message[1024];
497         char MajorStatus;
498         char username[256];
499
500         if (supplied_username != NULL) {
501                 safestrncpy(username, supplied_username, sizeof username);
502         }
503         else {
504                 safestrncpy(username, bstr("username"), sizeof username);
505         }
506
507         Buf = NewStrBuf();
508         serv_printf("AGUP %s", username);
509         StrBuf_ServGetln(Buf);
510         MajorStatus = ChrPtr(Buf)[0];
511         StrBufCutLeft(Buf, 4);
512         if (MajorStatus != '2') {
513                 /*TODO ImportantMessage */
514                 sprintf(error_message,
515                         "<img src=\"static/error.gif\" align=center>"
516                         "%s<br /><br />\n", ChrPtr(Buf));
517                 select_user_to_edit(error_message, username);
518                 FreeStrBuf(&Buf);
519                 return;
520         }
521         else {
522                 UL = NewUserListOneEntry(Buf);
523                 if (havebstr("edit_abe_button")) {
524                         display_edit_address_book_entry(username, UL->UID);
525                 }
526                 else if (havebstr("delete_button")) {
527                         delete_user(username);
528                 }
529                 else {
530                         WCTemplputParams SubTP;
531                         memset(&SubTP, 0, sizeof(WCTemplputParams));
532                         SubTP.Filter.ContextType = CTX_USERLIST;
533                         SubTP.Context = UL;
534                         output_headers(1, 0, 0, 0, 1, 0);
535                         DoTemplate(HKEY("userlist_detailview"), NULL, &SubTP);
536                         end_burst();
537                 }
538                 DeleteUserListEntry(UL);
539                 
540         }
541         FreeStrBuf(&Buf);
542 }
543
544 /**
545  *  do the backend operation of the user edit on the server
546  */
547 void edituser(void) {
548         char message[SIZ];
549         char buf[SIZ];
550         int is_new = 0;
551         unsigned int flags = 0;
552         char *username;
553
554         is_new = ibstr("is_new");
555         safestrncpy(message, "", sizeof message);
556         username = bstr("username");
557
558         if (!havebstr("ok_button")) {
559                 safestrncpy(message, _("Changes were not saved."), sizeof message);
560         }
561         
562         else {
563                 flags = ibstr("flags");
564                 if (yesbstr("inetmail")) {
565                         flags |= US_INTERNET;
566                 }
567                 else {
568                         flags &= ~US_INTERNET ;
569                 }
570
571                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
572                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
573                         serv_getln(buf, sizeof buf);
574                         if (buf[0] != '2') {
575                                 sprintf(&message[strlen(message)],
576                                         "<img src=\"static/error.gif\" align=center>"
577                                         "%s<br /><br />\n", &buf[4]);
578                         }
579                         else {
580                                 username = bstr("newname");
581                         }
582                 }
583
584                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
585                         username,
586                         bstr("password"),
587                         flags,
588                         bstr("timescalled"),
589                         bstr("msgsposted"),
590                         bstr("axlevel"),
591                         bstr("usernum"),
592                         bstr("lastcall"),
593                         bstr("purgedays")
594                 );
595                 serv_getln(buf, sizeof buf);
596                 if (buf[0] != '2') {
597                         sprintf(&message[strlen(message)],
598                                 "<img src=\"static/error.gif\" align=center>"
599                                 "%s<br /><br />\n", &buf[4]);
600                 }
601         }
602
603         /**
604          * If we are in the middle of creating a new user, move on to
605          * the vCard edit screen.
606          */
607         if (is_new) {
608                 display_edit_address_book_entry(username, lbstr("usernum") );
609         }
610         else {
611                 select_user_to_edit(message, username);
612         }
613 }
614
615 /*
616  *  burge a user 
617  *  username the name of the user to remove
618  */
619 void delete_user(char *username) {
620         char buf[SIZ];
621         char message[SIZ];
622
623         serv_printf("ASUP %s|0|0|0|0|0|", username);
624         serv_getln(buf, sizeof buf);
625         if (buf[0] != '2') {
626                 sprintf(message,
627                         "<img src=\"static/error.gif\" align=center>"
628                         "%s<br /><br />\n", &buf[4]);
629         }
630         else {
631                 safestrncpy(message, "", sizeof message);
632         }
633         select_user_to_edit(message, bstr("username"));
634 }
635                 
636
637
638 /**
639  *  create a new user
640  * take the web environment username and create it on the citadel server
641  */
642 void create_user(void) {
643         char buf[SIZ];
644         char error_message[SIZ];
645         char username[SIZ];
646
647         safestrncpy(username, bstr("username"), sizeof username);
648
649         serv_printf("CREU %s", username);
650         serv_getln(buf, sizeof buf);
651
652         if (buf[0] == '2') {
653                 sprintf(WC->ImportantMessage, _("A new user has been created."));
654                 display_edituser(username, 1);
655         }
656         else if (!strncmp(buf, "570", 3)) {
657                 sprintf(error_message,
658                         "<img src=\"static/error.gif\" align=center>"
659                         "%s<br /><br />\n",
660                         _("You are attempting to create a new user from within Citadel "
661                         "while running in host based authentication mode.  In this mode, "
662                         "you must create new users on the host system, not within Citadel.")
663                 );
664                 select_user_to_edit(error_message, NULL);
665         }
666         else {
667                 sprintf(error_message,
668                         "<img src=\"static/error.gif\" align=center>"
669                         "%s<br /><br />\n", &buf[4]);
670                 select_user_to_edit(error_message, NULL);
671         }
672
673 }
674
675
676 void _select_user_to_edit(void){select_user_to_edit(NULL, NULL);}
677 void _display_edituser(void) {display_edituser(NULL, 0);}
678
679 void 
680 InitModule_USEREDIT
681 (void)
682 {
683         WebcitAddUrlHandler(HKEY("select_user_to_edit"), _select_user_to_edit, 0);
684         WebcitAddUrlHandler(HKEY("display_edituser"), _display_edituser, 0);
685         WebcitAddUrlHandler(HKEY("edituser"), edituser, 0);
686         WebcitAddUrlHandler(HKEY("create_user"), create_user, 0);
687
688         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, CTX_USERLIST);
689         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, CTX_USERLIST);
690         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, CTX_USERLIST);
691         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, CTX_USERLIST);
692         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, CTX_USERLIST);
693         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, CTX_USERLIST);
694         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, CTX_USERLIST);
695         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, CTX_USERLIST);
696                                                     
697         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, CTX_USERLIST);
698         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, CTX_USERLIST);
699
700         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
701         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
702         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
703
704         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_NOFLAG);
705
706
707         RegisterSortFunc(HKEY("user:name"),
708                          HKEY("userlist"),
709                          CompareUserListName,
710                          CompareUserListNameRev,
711                          GroupchangeUserListName,
712                          CTX_USERLIST);
713         RegisterSortFunc(HKEY("user:accslvl"),
714                          HKEY("userlist"),
715                          CompareAccessLevel,
716                          CompareAccessLevelRev,
717                          GroupchangeAccessLevel,
718                          CTX_USERLIST);
719
720         RegisterSortFunc(HKEY("user:nlogons"),
721                          HKEY("userlist"),
722                          ComparenLogons,
723                          ComparenLogonsRev,
724                          GroupchangenLogons,
725                          CTX_USERLIST);
726
727         RegisterSortFunc(HKEY("user:uid"),
728                          HKEY("userlist"),
729                          CompareUID,
730                          CompareUIDRev,
731                          GroupchangeUID,
732                          CTX_USERLIST);
733
734         RegisterSortFunc(HKEY("user:lastlogon"),
735                          HKEY("userlist"),
736                          CompareLastLogon,
737                          CompareLastLogonRev,
738                          GroupchangeLastLogon,
739                          CTX_USERLIST);
740
741         RegisterSortFunc(HKEY("user:nmsgposts"),
742                          HKEY("userlist"),
743                          ComparenPosts,
744                          ComparenPostsRev,
745                          GroupchangenPosts,
746                          CTX_USERLIST);
747
748 }