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