* remove old (replaced) code
[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*) vUser1;
97         UserListEntry *u2 = (UserListEntry*) 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*) vUser1;
104         UserListEntry *u2 = (UserListEntry*) vUser2;
105         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
106 }
107
108 /*
109  * Sort by AccessLevel
110  */
111 int CompareAccessLevel(const void *vUser1, const void *vUser2)
112 {
113         UserListEntry *u1 = (UserListEntry*) vUser1;
114         UserListEntry *u2 = (UserListEntry*) vUser2;
115
116         return (u1->AccessLevel > u2->AccessLevel);
117 }
118 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
119 {
120         UserListEntry *u1 = (UserListEntry*) vUser1;
121         UserListEntry *u2 = (UserListEntry*) vUser2;
122
123         return (u2->AccessLevel > u1->AccessLevel);
124 }
125
126
127 /*
128  * Sort by UID
129  */
130 int CompareUID(const void *vUser1, const void *vUser2)
131 {
132         UserListEntry *u1 = (UserListEntry*) vUser1;
133         UserListEntry *u2 = (UserListEntry*) vUser2;
134
135         return (u1->UID > u2->UID);
136 }
137 int CompareUIDRev(const void *vUser1, const void *vUser2)
138 {
139         UserListEntry *u1 = (UserListEntry*) vUser1;
140         UserListEntry *u2 = (UserListEntry*) vUser2;
141
142         return (u2->UID > u1->UID);
143 }
144
145 /*
146  * Sort By Date /// TODO!
147  */
148 int CompareLastLogon(const void *vUser1, const void *vUser2)
149 {
150         UserListEntry *u1 = (UserListEntry*) vUser1;
151         UserListEntry *u2 = (UserListEntry*) vUser2;
152
153         return (u1->LastLogonT > u2->LastLogonT);
154 }
155 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
156 {
157         UserListEntry *u1 = (UserListEntry*) vUser1;
158         UserListEntry *u2 = (UserListEntry*) vUser2;
159
160         return (u2->LastLogonT > u1->LastLogonT);
161 }
162
163 /*
164  * Sort By Number of Logons
165  */
166 int ComparenLogons(const void *vUser1, const void *vUser2)
167 {
168         UserListEntry *u1 = (UserListEntry*) vUser1;
169         UserListEntry *u2 = (UserListEntry*) vUser2;
170
171         return (u1->nLogons > u2->nLogons);
172 }
173 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
174 {
175         UserListEntry *u1 = (UserListEntry*) vUser1;
176         UserListEntry *u2 = (UserListEntry*) vUser2;
177
178         return (u2->nLogons > u1->nLogons);
179 }
180
181 /*
182  * Sort By Number of Posts
183  */
184 int ComparenPosts(const void *vUser1, const void *vUser2)
185 {
186         UserListEntry *u1 = (UserListEntry*) vUser1;
187         UserListEntry *u2 = (UserListEntry*) vUser2;
188
189         return (u1->nPosts > u2->nPosts);
190 }
191 int ComparenPostsRev(const void *vUser1, const void *vUser2)
192 {
193         UserListEntry *u1 = (UserListEntry*) vUser1;
194         UserListEntry *u2 = (UserListEntry*) vUser2;
195
196         return (u2->nPosts > u1->nPosts);
197 }
198
199
200 HashList *iterate_load_userlist(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
201 {
202         HashList *Hash;
203         char buf[SIZ];
204         StrBuf *Buf;
205         UserListEntry* ul;
206         char nnn[64];
207         int nUsed;
208         int Order;
209         int len;
210         
211         serv_puts("LIST");
212         serv_getln(buf, sizeof buf);
213         if (buf[0] == '1') {
214                 Hash = NewHash(1, NULL);
215
216                 Buf = NewStrBuf();
217                 while ((len = StrBuf_ServGetln(Buf),
218                         strcmp(ChrPtr(Buf), "000"))) {
219                         ul = NewUserListEntry(Buf);
220                         if (ul == NULL)
221                                 continue;
222                         nUsed = GetCount(Hash);
223                         nUsed = snprintf(nnn, sizeof(nnn), "%d", nUsed+1);
224                         Put(Hash, nnn, nUsed, ul, DeleteUserListEntry); 
225                 }
226                 FreeStrBuf(&Buf);
227                 Order = ibstr("SortOrder");
228                 switch (ibstr("SortBy")){
229                 case 1: /*NAME*/
230                         SortByPayload(Hash, (Order)? 
231                                       CompareUserListName:
232                                       CompareUserListNameRev);
233                         break;
234                 case 2: /*AccessLevel*/
235                         SortByPayload(Hash, (Order)? 
236                                       CompareAccessLevel:
237                                       CompareAccessLevelRev);
238                         break;
239                 case 3: /*nLogons*/
240                         SortByPayload(Hash, (Order)? 
241                                       ComparenLogons:
242                                       ComparenLogonsRev);
243                         break;
244                 case 4: /*UID*/
245                         SortByPayload(Hash, (Order)? 
246                                       CompareUID:
247                                       CompareUIDRev);
248                         break;
249                 case 5: /*LastLogon*/
250                         SortByPayload(Hash, (Order)? 
251                                       CompareLastLogon:
252                                       CompareLastLogonRev);
253                         break;
254                 case 6: /* nLogons */
255                         SortByPayload(Hash, (Order)? 
256                                       ComparenLogons:
257                                       ComparenLogonsRev);
258                         break;
259                 case 7: /* Posts */
260                         SortByPayload(Hash, (Order)? 
261                                       ComparenPosts:
262                                       ComparenPostsRev);
263                         break;
264                 }
265                 return Hash;
266         }
267         return NULL;
268 }
269
270
271 void tmplput_USERLIST_UserName(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
272 {
273         UserListEntry *ul = (UserListEntry*) Context;
274         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, ul->UserName, 0);
275 }
276
277 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
278 {
279         UserListEntry *ul = (UserListEntry*) Context;
280
281         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
282 }
283
284 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
285 {
286         UserListEntry *ul = (UserListEntry*) Context;
287         
288         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
289 }
290
291 void tmplput_USERLIST_UID(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
292 {
293         UserListEntry *ul = (UserListEntry*) Context;
294
295         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
296 }
297
298 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
299 {
300         UserListEntry *ul = (UserListEntry*) Context;
301
302         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
303 }
304 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
305 {
306         UserListEntry *ul = (UserListEntry*) Context;
307         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
308 }
309
310 void tmplput_USERLIST_nLogons(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
311 {
312         UserListEntry *ul = (UserListEntry*) Context;
313
314         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
315 }
316
317 void tmplput_USERLIST_nPosts(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
318 {
319         UserListEntry *ul = (UserListEntry*) Context;
320
321         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
322 }
323
324 void tmplput_USERLIST_Flags(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
325 {
326         UserListEntry *ul = (UserListEntry*) Context;
327
328         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
329 }
330
331 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
332 {
333         UserListEntry *ul = (UserListEntry*) Context;
334
335         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
336 }
337
338 int ConditionalUser(WCTemplateToken *Tokens, void *Context, int ContextType)
339 {
340         UserListEntry *ul = (UserListEntry*) Context;
341         if (havebstr("usernum")) {
342                 return ibstr("usernum") == ul->UID;
343         }
344         else if (havebstr("username")) {
345                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
346         }
347         else 
348                 return 0;
349 }
350
351 int ConditionalFlagINetEmail(WCTemplateToken *Tokens, void *Context, int ContextType)
352 {
353         UserListEntry *ul = (UserListEntry*) Context;
354         return (ul->Flags & US_INTERNET) != 0;
355 }
356
357 int ConditionalUserAccess(WCTemplateToken *Tokens, void *Context, int ContextType)
358 {
359         UserListEntry *ul = (UserListEntry*) Context;
360
361         if (Tokens->Params[3]->Type == TYPE_LONG)
362                 return (Tokens->Params[3]->lvalue == ul->AccessLevel);
363         else
364                 return 0;
365 }
366
367 /**
368  *  Locate the message number of a user's vCard in the current room
369  *  username the plaintext name of the user
370  *  usernum the number of the user on the citadel server
371  * \return the message id of his vcard
372  */
373 long locate_user_vcard(char *username, long usernum) {
374         char buf[SIZ];
375         long vcard_msgnum = (-1L);
376         char content_type[SIZ];
377         char partnum[SIZ];
378         int already_tried_creating_one = 0;
379
380         struct stuff_t {
381                 struct stuff_t *next;
382                 long msgnum;
383         };
384
385         struct stuff_t *stuff = NULL;
386         struct stuff_t *ptr;
387
388 TRYAGAIN:
389         /** Search for the user's vCard */
390         serv_puts("MSGS ALL");
391         serv_getln(buf, sizeof buf);
392         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
393                 ptr = malloc(sizeof(struct stuff_t));
394                 ptr->msgnum = atol(buf);
395                 ptr->next = stuff;
396                 stuff = ptr;
397         }
398
399         /** Iterate through the message list looking for vCards */
400         while (stuff != NULL) {
401                 serv_printf("MSG0 %ld|2", stuff->msgnum);
402                 serv_getln(buf, sizeof buf);
403                 if (buf[0]=='1') {
404                         while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
405                                 if (!strncasecmp(buf, "part=", 5)) {
406                                         extract_token(partnum, &buf[5], 2, '|', sizeof partnum);
407                                         extract_token(content_type, &buf[5], 4, '|', sizeof content_type);
408                                         if (  (!strcasecmp(content_type, "text/x-vcard"))
409                                            || (!strcasecmp(content_type, "text/vcard")) ) {
410                                                 vcard_msgnum = stuff->msgnum;
411                                         }
412                                 }
413                         }
414                 }
415
416                 ptr = stuff->next;
417                 free(stuff);
418                 stuff = ptr;
419         }
420
421         /** If there's no vcard, create one */
422         if ((vcard_msgnum < 0) && (already_tried_creating_one == 0)) {
423                 already_tried_creating_one = 1;
424                 serv_puts("ENT0 1|||4");
425                 serv_getln(buf, sizeof buf);
426                 if (buf[0] == '4') {
427                         serv_puts("Content-type: text/x-vcard");
428                         serv_puts("");
429                         serv_puts("begin:vcard");
430                         serv_puts("end:vcard");
431                         serv_puts("000");
432                 }
433                 goto TRYAGAIN;
434         }
435
436         return(vcard_msgnum);
437 }
438
439
440 /**
441  *  Display the form for editing a user's address book entry
442  *  username the name of the user
443  *  usernum the citadel-uid of the user
444  */
445 void display_edit_address_book_entry(char *username, long usernum) {
446         char roomname[SIZ];
447         char buf[SIZ];
448         char error_message[SIZ];
449         long vcard_msgnum = (-1L);
450
451         /** Locate the user's config room, creating it if necessary */
452         sprintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
453         serv_printf("GOTO %s||1", roomname);
454         serv_getln(buf, sizeof buf);
455         if (buf[0] != '2') {
456                 serv_printf("CRE8 1|%s|5|||1|", roomname);
457                 serv_getln(buf, sizeof buf);
458                 serv_printf("GOTO %s||1", roomname);
459                 serv_getln(buf, sizeof buf);
460                 if (buf[0] != '2') {
461                         sprintf(error_message,
462                                 "<img src=\"static/error.gif\" align=center>"
463                                 "%s<br /><br />\n", &buf[4]);
464                         select_user_to_edit(error_message, username);
465                         return;
466                 }
467         }
468
469         vcard_msgnum = locate_user_vcard(username, usernum);
470
471         if (vcard_msgnum < 0) {
472                 sprintf(error_message,
473                         "<img src=\"static/error.gif\" align=center>%s<br /><br />\n",
474                         _("An error occurred while trying to create or edit this address book entry.")
475                 );
476                 select_user_to_edit(error_message, username);
477                 return;
478         }
479
480         do_edit_vcard(vcard_msgnum, "1", "select_user_to_edit", roomname);
481 }
482
483
484 void display_edituser(char *supplied_username, int is_new) {
485         UserListEntry* UL;
486         StrBuf *Buf;
487         char error_message[1024];
488         char MajorStatus;
489         char username[256];
490
491         if (supplied_username != NULL) {
492                 safestrncpy(username, supplied_username, sizeof username);
493         }
494         else {
495                 safestrncpy(username, bstr("username"), sizeof username);
496         }
497
498         Buf = NewStrBuf();
499         serv_printf("AGUP %s", username);
500         StrBuf_ServGetln(Buf);
501         MajorStatus = ChrPtr(Buf)[0];
502         StrBufCutLeft(Buf, 4);
503         if (MajorStatus != '2') {
504                 ///TODO ImportantMessage
505                 sprintf(error_message,
506                         "<img src=\"static/error.gif\" align=center>"
507                         "%s<br /><br />\n", ChrPtr(Buf));
508                 select_user_to_edit(error_message, username);
509                 FreeStrBuf(&Buf);
510                 return;
511         }
512         else {
513                 UL = NewUserListOneEntry(Buf);
514                 if (havebstr("edit_abe_button")) {
515                         display_edit_address_book_entry(username, UL->UID);
516                 }
517                 else if (havebstr("delete_button")) {
518                         delete_user(username);
519                 }
520                 else {
521                         output_headers(1, 0, 0, 0, 1, 0);
522                         DoTemplate(HKEY("userlist_detailview"), NULL, (void*) UL, CTX_USERLIST);
523                         end_burst();
524                 }
525                 DeleteUserListEntry(UL);
526                 
527         }
528         FreeStrBuf(&Buf);
529 }
530
531 /**
532  *  do the backend operation of the user edit on the server
533  */
534 void edituser(void) {
535         char message[SIZ];
536         char buf[SIZ];
537         int is_new = 0;
538         unsigned int flags = 0;
539         char *username;
540
541         is_new = ibstr("is_new");
542         safestrncpy(message, "", sizeof message);
543         username = bstr("username");
544
545         if (!havebstr("ok_button")) {
546                 safestrncpy(message, _("Changes were not saved."), sizeof message);
547         }
548         
549         else {
550                 flags = ibstr("flags");
551                 if (yesbstr("inetmail")) {
552                         flags |= US_INTERNET;
553                 }
554                 else {
555                         flags &= ~US_INTERNET ;
556                 }
557
558                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
559                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
560                         serv_getln(buf, sizeof buf);
561                         if (buf[0] != '2') {
562                                 sprintf(&message[strlen(message)],
563                                         "<img src=\"static/error.gif\" align=center>"
564                                         "%s<br /><br />\n", &buf[4]);
565                         }
566                         else {
567                                 username = bstr("newname");
568                         }
569                 }
570
571                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
572                         username,
573                         bstr("password"),
574                         flags,
575                         bstr("timescalled"),
576                         bstr("msgsposted"),
577                         bstr("axlevel"),
578                         bstr("usernum"),
579                         bstr("lastcall"),
580                         bstr("purgedays")
581                 );
582                 serv_getln(buf, sizeof buf);
583                 if (buf[0] != '2') {
584                         sprintf(&message[strlen(message)],
585                                 "<img src=\"static/error.gif\" align=center>"
586                                 "%s<br /><br />\n", &buf[4]);
587                 }
588         }
589
590         /**
591          * If we are in the middle of creating a new user, move on to
592          * the vCard edit screen.
593          */
594         if (is_new) {
595                 display_edit_address_book_entry(username, lbstr("usernum") );
596         }
597         else {
598                 select_user_to_edit(message, username);
599         }
600 }
601
602 /*
603  *  burge a user 
604  *  username the name of the user to remove
605  */
606 void delete_user(char *username) {
607         char buf[SIZ];
608         char message[SIZ];
609
610         serv_printf("ASUP %s|0|0|0|0|0|", username);
611         serv_getln(buf, sizeof buf);
612         if (buf[0] != '2') {
613                 sprintf(message,
614                         "<img src=\"static/error.gif\" align=center>"
615                         "%s<br /><br />\n", &buf[4]);
616         }
617         else {
618                 safestrncpy(message, "", sizeof message);
619         }
620         select_user_to_edit(message, bstr("username"));
621 }
622                 
623
624
625 /**
626  *  create a new user
627  * take the web environment username and create it on the citadel server
628  */
629 void create_user(void) {
630         char buf[SIZ];
631         char error_message[SIZ];
632         char username[SIZ];
633
634         safestrncpy(username, bstr("username"), sizeof username);
635
636         serv_printf("CREU %s", username);
637         serv_getln(buf, sizeof buf);
638
639         if (buf[0] == '2') {
640                 sprintf(WC->ImportantMessage, _("A new user has been created."));
641                 display_edituser(username, 1);
642         }
643         else if (!strncmp(buf, "570", 3)) {
644                 sprintf(error_message,
645                         "<img src=\"static/error.gif\" align=center>"
646                         "%s<br /><br />\n",
647                         _("You are attempting to create a new user from within Citadel "
648                         "while running in host based authentication mode.  In this mode, "
649                         "you must create new users on the host system, not within Citadel.")
650                 );
651                 select_user_to_edit(error_message, NULL);
652         }
653         else {
654                 sprintf(error_message,
655                         "<img src=\"static/error.gif\" align=center>"
656                         "%s<br /><br />\n", &buf[4]);
657                 select_user_to_edit(error_message, NULL);
658         }
659
660 }
661
662
663 void _select_user_to_edit(void){select_user_to_edit(NULL, NULL);}
664 void _display_edituser(void) {display_edituser(NULL, 0);}
665
666 void 
667 InitModule_USEREDIT
668 (void)
669 {
670         WebcitAddUrlHandler(HKEY("select_user_to_edit"), _select_user_to_edit, 0);
671         WebcitAddUrlHandler(HKEY("display_edituser"), _display_edituser, 0);
672         WebcitAddUrlHandler(HKEY("edituser"), edituser, 0);
673         WebcitAddUrlHandler(HKEY("create_user"), create_user, 0);
674
675         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, CTX_USERLIST);
676         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, CTX_USERLIST);
677         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, CTX_USERLIST);
678         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, CTX_USERLIST);
679         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, CTX_USERLIST);
680         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, CTX_USERLIST);
681         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, CTX_USERLIST);
682         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, CTX_USERLIST);
683                                                     
684         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, CTX_USERLIST);
685         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, CTX_USERLIST);
686
687         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
688         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
689         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
690
691         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE);
692 }