* migrate userlist to templating.
[citadel.git] / webcit / useredit.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup AdminTasks Administrative screen to add/change/delete user accounts
6  * \ingroup CitadelConfig
7  *
8  */
9 /*@{*/
10
11 #include "webcit.h"
12 #include "webserver.h"
13
14
15 /**
16  * \brief show a list of available users to edit them
17  * \param message the header message???
18  * \param preselect which user should be selected in the browser
19  */
20 void select_user_to_edit(char *message, char *preselect)
21 {/*
22         char buf[SIZ];
23         char username[SIZ];
24  */
25         output_headers(1, 0, 0, 0, 1, 0);
26         do_template("edituser_select", NULL);
27         end_burst();
28
29 /*
30
31         output_headers(1, 1, 2, 0, 0, 0);
32         wprintf("<div id=\"banner\">\n");
33         wprintf("<img src=\"static/usermanag_48x.gif\">");
34         wprintf("<h1>");
35         wprintf(_("Edit or delete users"));
36         wprintf("</h1>");
37         wprintf("</div>");
38
39         wprintf("<div id=\"content\" class=\"service\">\n");
40
41         if (message != NULL) wprintf(message);
42
43         wprintf("<table border=0 cellspacing=10><tr valign=top><td>\n");
44
45         svput("BOXTITLE", WCS_STRING, _("Add users"));
46         do_template("beginbox", NULL);
47
48         wprintf(_("To create a new user account, enter the desired "
49                 "user name in the box below and click 'Create'."));
50         wprintf("<br /><br />");
51
52         wprintf("<center><form method=\"POST\" action=\"create_user\">\n");
53         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
54         wprintf(_("New user: "));
55         wprintf("<input type=\"text\" name=\"username\"><br />\n"
56                 "<input type=\"submit\" name=\"create_button\" value=\"%s\">"
57                 "</form></center>\n", _("Create"));
58
59         do_template("endbox", NULL);
60
61         wprintf("</td><td>");
62
63         svput("BOXTITLE", WCS_STRING, _("Edit or Delete users"));
64         do_template("beginbox", NULL);
65
66         wprintf(_("To edit an existing user account, select the user "
67                 "name from the list and click 'Edit'."));
68         wprintf("<br /><br />");
69         
70         wprintf("<center>"
71                 "<form method=\"POST\" action=\"display_edituser\">\n");
72         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
73         wprintf("<select name=\"username\" size=10 style=\"width:100%%\">\n");
74         serv_puts("LIST");
75         serv_getln(buf, sizeof buf);
76         if (buf[0] == '1') {
77                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
78                         extract_token(username, buf, 0, '|', sizeof username);
79                         wprintf("<option");
80                         if (preselect != NULL)
81                            if (!strcasecmp(username, preselect))
82                               wprintf(" selected");
83                         wprintf(">");
84                         escputs(username);
85                         wprintf("\n");
86                 }
87         }
88         wprintf("</select><br />\n");
89
90         wprintf("<input type=\"submit\" name=\"edit_config_button\" value=\"%s\">", _("Edit configuration"));
91         wprintf("<input type=\"submit\" name=\"edit_abe_button\" value=\"%s\">", _("Edit address book entry"));
92         wprintf("<input type=\"submit\" name=\"delete_button\" value=\"%s\" "
93                 "onClick=\"return confirm('%s');\">", _("Delete user"), _("Delete this user?"));
94         wprintf("</form></center>\n");
95         do_template("endbox", NULL);
96
97         wprintf("</td></tr></table>\n");
98
99         wDumpContent(1);
100 */
101 }
102
103
104 typedef struct _UserListEntry {
105         StrBuf *UserName;
106         int AccessLevel;
107         int UID;
108         StrBuf *LastLogon;
109         time_t LastLogonT;
110         int nLogons;
111         int nPosts;
112         StrBuf *Passvoid;
113 } UserListEntry;
114
115 void DeleteUserListEntry(void *vUserList)
116 {
117         UserListEntry *ul = (UserListEntry*) vUserList;
118         FreeStrBuf(&ul->UserName);
119         FreeStrBuf(&ul->LastLogon);
120         FreeStrBuf(&ul->Passvoid);
121         free(ul);
122 }
123
124 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
125 {
126         UserListEntry *ul;
127
128         if (StrLength(SerializedUserList) < 8) 
129                 return NULL;
130
131         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
132         ul->UserName = NewStrBuf();
133         ul->LastLogon = NewStrBuf();
134         ul->Passvoid = NewStrBuf();
135
136         StrBufExtract_token(ul->UserName, SerializedUserList, 0, '|');
137         ul->AccessLevel = StrBufExtract_int(SerializedUserList, 1, '|');
138         ul->UID = StrBufExtract_int(SerializedUserList, 2, '|');
139         StrBufExtract_token(ul->LastLogon, SerializedUserList, 3, '|');
140         /// TODO: ul->LastLogon -> ulLastLogonT
141         ul->nLogons = StrBufExtract_int(SerializedUserList, 4, '|');
142         ul->nPosts = StrBufExtract_int(SerializedUserList, 5, '|');
143         StrBufExtract_token(ul->Passvoid, SerializedUserList, 6, '|');
144
145         return ul;
146 }
147
148 /*
149  * Sort by Username
150  */
151 int CompareUserListName(const void *vUser1, const void *vUser2)
152 {
153         UserListEntry *u1 = (UserListEntry*) vUser1;
154         UserListEntry *u2 = (UserListEntry*) vUser2;
155
156         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
157 }
158 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
159 {
160         UserListEntry *u1 = (UserListEntry*) vUser1;
161         UserListEntry *u2 = (UserListEntry*) vUser2;
162         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
163 }
164
165 /*
166  * Sort by AccessLevel
167  */
168 int CompareAccessLevel(const void *vUser1, const void *vUser2)
169 {
170         UserListEntry *u1 = (UserListEntry*) vUser1;
171         UserListEntry *u2 = (UserListEntry*) vUser2;
172
173         return (u1->AccessLevel > u2->AccessLevel);
174 }
175 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
176 {
177         UserListEntry *u1 = (UserListEntry*) vUser1;
178         UserListEntry *u2 = (UserListEntry*) vUser2;
179
180         return (u2->AccessLevel > u1->AccessLevel);
181 }
182
183
184 /*
185  * Sort by UID
186  */
187 int CompareUID(const void *vUser1, const void *vUser2)
188 {
189         UserListEntry *u1 = (UserListEntry*) vUser1;
190         UserListEntry *u2 = (UserListEntry*) vUser2;
191
192         return (u1->UID > u2->UID);
193 }
194 int CompareUIDRev(const void *vUser1, const void *vUser2)
195 {
196         UserListEntry *u1 = (UserListEntry*) vUser1;
197         UserListEntry *u2 = (UserListEntry*) vUser2;
198
199         return (u2->UID > u1->UID);
200 }
201
202 /*
203  * Sort By Date /// TODO!
204  */
205 int CompareLastLogon(const void *vUser1, const void *vUser2)
206 {
207         UserListEntry *u1 = (UserListEntry*) vUser1;
208         UserListEntry *u2 = (UserListEntry*) vUser2;
209
210         return (u1->LastLogonT > u2->LastLogonT);
211 }
212 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
213 {
214         UserListEntry *u1 = (UserListEntry*) vUser1;
215         UserListEntry *u2 = (UserListEntry*) vUser2;
216
217         return (u2->LastLogonT > u1->LastLogonT);
218 }
219
220 /*
221  * Sort By Number of Logons
222  */
223 int ComparenLogons(const void *vUser1, const void *vUser2)
224 {
225         UserListEntry *u1 = (UserListEntry*) vUser1;
226         UserListEntry *u2 = (UserListEntry*) vUser2;
227
228         return (u1->nLogons > u2->nLogons);
229 }
230 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
231 {
232         UserListEntry *u1 = (UserListEntry*) vUser1;
233         UserListEntry *u2 = (UserListEntry*) vUser2;
234
235         return (u2->nLogons > u1->nLogons);
236 }
237
238 /*
239  * Sort By Number of Posts
240  */
241 int ComparenPosts(const void *vUser1, const void *vUser2)
242 {
243         UserListEntry *u1 = (UserListEntry*) vUser1;
244         UserListEntry *u2 = (UserListEntry*) vUser2;
245
246         return (u1->nPosts > u2->nPosts);
247 }
248 int ComparenPostsRev(const void *vUser1, const void *vUser2)
249 {
250         UserListEntry *u1 = (UserListEntry*) vUser1;
251         UserListEntry *u2 = (UserListEntry*) vUser2;
252
253         return (u2->nPosts > u1->nPosts);
254 }
255
256
257 HashList *iterate_load_userlist(WCTemplateToken *Token)
258 {
259         HashList *Hash;
260         char buf[SIZ];
261         StrBuf *Buf;
262         UserListEntry* ul;
263         char nnn[64];
264         int nUsed;
265         int Order;
266         int len;
267         
268         serv_puts("LIST");
269         serv_getln(buf, sizeof buf);
270         if (buf[0] == '1') {
271                 Hash = NewHash(1, NULL);
272
273                 Buf = NewStrBuf();
274                 while ((len = StrBuf_ServGetln(Buf),
275                         strcmp(ChrPtr(Buf), "000"))) {
276                         ul = NewUserListEntry(Buf);
277                         if (ul == NULL)
278                                 continue;
279                         nUsed = GetCount(Hash);
280                         nUsed = snprintf(nnn, sizeof(nnn), "%d", nUsed+1);
281                         Put(Hash, nnn, nUsed, ul, DeleteUserListEntry); 
282                 }
283                 FreeStrBuf(&Buf);
284                 Order = ibstr("SortOrder");
285                 switch (ibstr("SortBy")){
286                 case 1: /*NAME*/
287                         SortByPayload(Hash, (Order)? 
288                                       CompareUserListName:
289                                       CompareUserListNameRev);
290                         break;
291                 case 2: /*AccessLevel*/
292                         SortByPayload(Hash, (Order)? 
293                                       CompareAccessLevel:
294                                       CompareAccessLevelRev);
295                         break;
296                 case 3: /*nLogons*/
297                         SortByPayload(Hash, (Order)? 
298                                       ComparenLogons:
299                                       ComparenLogonsRev);
300                         break;
301                 case 4: /*UID*/
302                         SortByPayload(Hash, (Order)? 
303                                       CompareUID:
304                                       CompareUIDRev);
305                         break;
306                 case 5: /*LastLogon*/
307                         SortByPayload(Hash, (Order)? 
308                                       CompareLastLogon:
309                                       CompareLastLogonRev);
310                         break;
311                 case 6: /* nLogons */
312                         SortByPayload(Hash, (Order)? 
313                                       ComparenLogons:
314                                       ComparenLogonsRev);
315                         break;
316                 case 7: /* Posts */
317                         SortByPayload(Hash, (Order)? 
318                                       ComparenPosts:
319                                       ComparenPostsRev);
320                         break;
321                 }
322                 return Hash;
323         }
324         return NULL;
325 }
326
327
328 void tmplput_USERLIST_UserName(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
329 {
330         UserListEntry *ul = (UserListEntry*) Context;
331 /// TODO: X
332         StrBufAppendBuf(Target, ul->UserName, 0);
333 }
334
335 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
336 {
337         UserListEntry *ul = (UserListEntry*) Context;
338
339         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
340 }
341
342 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
343 {
344         UserListEntry *ul = (UserListEntry*) Context;
345         
346         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
347 }
348
349 void tmplput_USERLIST_UID(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
350 {
351         UserListEntry *ul = (UserListEntry*) Context;
352
353         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
354 }
355
356 void tmplput_USERLIST_LastLogon(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
357 {
358         UserListEntry *ul = (UserListEntry*) Context;
359
360         StrBufAppendBuf(Target, ul->LastLogon, 0);
361 }
362
363 void tmplput_USERLIST_nLogons(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
364 {
365         UserListEntry *ul = (UserListEntry*) Context;
366
367         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
368 }
369
370 void tmplput_USERLIST_nPosts(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
371 {
372         UserListEntry *ul = (UserListEntry*) Context;
373
374         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
375 }
376
377 int ConditionalUser(WCTemplateToken *Tokens, void *Context, int ContextType)
378 {
379         UserListEntry *ul = (UserListEntry*) Context;
380         if (havebstr("usernum")) {
381                 return ibstr("usernum") == ul->UID;
382         }
383         else if (havebstr("username")) {
384                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
385         }
386         else 
387                 return 0;
388 }
389  
390 /**
391  * \brief Locate the message number of a user's vCard in the current room
392  * \param username the plaintext name of the user
393  * \param usernum the number of the user on the citadel server
394  * \return the message id of his vcard
395  */
396 long locate_user_vcard(char *username, long usernum) {
397         char buf[SIZ];
398         long vcard_msgnum = (-1L);
399         char content_type[SIZ];
400         char partnum[SIZ];
401         int already_tried_creating_one = 0;
402
403         struct stuff_t {
404                 struct stuff_t *next;
405                 long msgnum;
406         };
407
408         struct stuff_t *stuff = NULL;
409         struct stuff_t *ptr;
410
411 TRYAGAIN:
412         /** Search for the user's vCard */
413         serv_puts("MSGS ALL");
414         serv_getln(buf, sizeof buf);
415         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
416                 ptr = malloc(sizeof(struct stuff_t));
417                 ptr->msgnum = atol(buf);
418                 ptr->next = stuff;
419                 stuff = ptr;
420         }
421
422         /** Iterate through the message list looking for vCards */
423         while (stuff != NULL) {
424                 serv_printf("MSG0 %ld|2", stuff->msgnum);
425                 serv_getln(buf, sizeof buf);
426                 if (buf[0]=='1') {
427                         while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
428                                 if (!strncasecmp(buf, "part=", 5)) {
429                                         extract_token(partnum, &buf[5], 2, '|', sizeof partnum);
430                                         extract_token(content_type, &buf[5], 4, '|', sizeof content_type);
431                                         if (  (!strcasecmp(content_type, "text/x-vcard"))
432                                            || (!strcasecmp(content_type, "text/vcard")) ) {
433                                                 vcard_msgnum = stuff->msgnum;
434                                         }
435                                 }
436                         }
437                 }
438
439                 ptr = stuff->next;
440                 free(stuff);
441                 stuff = ptr;
442         }
443
444         /** If there's no vcard, create one */
445         if (vcard_msgnum < 0) if (already_tried_creating_one == 0) {
446                 already_tried_creating_one = 1;
447                 serv_puts("ENT0 1|||4");
448                 serv_getln(buf, sizeof buf);
449                 if (buf[0] == '4') {
450                         serv_puts("Content-type: text/x-vcard");
451                         serv_puts("");
452                         serv_puts("begin:vcard");
453                         serv_puts("end:vcard");
454                         serv_puts("000");
455                 }
456                 goto TRYAGAIN;
457         }
458
459         return(vcard_msgnum);
460 }
461
462
463 /**
464  * \brief Display the form for editing a user's address book entry
465  * \param username the name of the user
466  * \param usernum the citadel-uid of the user
467  */
468 void display_edit_address_book_entry(char *username, long usernum) {
469         char roomname[SIZ];
470         char buf[SIZ];
471         char error_message[SIZ];
472         long vcard_msgnum = (-1L);
473
474         /** Locate the user's config room, creating it if necessary */
475         sprintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
476         serv_printf("GOTO %s||1", roomname);
477         serv_getln(buf, sizeof buf);
478         if (buf[0] != '2') {
479                 serv_printf("CRE8 1|%s|5|||1|", roomname);
480                 serv_getln(buf, sizeof buf);
481                 serv_printf("GOTO %s||1", roomname);
482                 serv_getln(buf, sizeof buf);
483                 if (buf[0] != '2') {
484                         sprintf(error_message,
485                                 "<img src=\"static/error.gif\" align=center>"
486                                 "%s<br /><br />\n", &buf[4]);
487                         select_user_to_edit(error_message, username);
488                         return;
489                 }
490         }
491
492         vcard_msgnum = locate_user_vcard(username, usernum);
493
494         if (vcard_msgnum < 0) {
495                 sprintf(error_message,
496                         "<img src=\"static/error.gif\" align=center>%s<br /><br />\n",
497                         _("An error occurred while trying to create or edit this address book entry.")
498                 );
499                 select_user_to_edit(error_message, username);
500                 return;
501         }
502
503         do_edit_vcard(vcard_msgnum, "1", "select_user_to_edit", roomname);
504 }
505
506
507
508
509 /**
510  * \brief Edit a user.  
511  * If supplied_username is null, look in the "username"
512  * web variable for the name of the user to edit.
513  * 
514  * If "is_new" is set to nonzero, this screen will set the web variables
515  * to send the user to the vCard editor next.
516  * \param supplied_username user to look up or NULL if to search in the environment
517  * \param is_new should we create the user?
518  */
519 void display_edituser(char *supplied_username, int is_new) {
520         char buf[1024];
521         char error_message[1024];
522         time_t now;
523
524         char username[256];
525         char password[256];
526         unsigned int flags;
527         int timescalled;
528         int msgsposted;
529         int axlevel;
530         long usernum;
531         time_t lastcall;
532         int purgedays;
533         int i;
534
535         if (supplied_username != NULL) {
536                 safestrncpy(username, supplied_username, sizeof username);
537         }
538         else {
539                 safestrncpy(username, bstr("username"), sizeof username);
540         }
541
542         serv_printf("AGUP %s", username);
543         serv_getln(buf, sizeof buf);
544         if (buf[0] != '2') {
545                 sprintf(error_message,
546                         "<img src=\"static/error.gif\" align=center>"
547                         "%s<br /><br />\n", &buf[4]);
548                 select_user_to_edit(error_message, username);
549                 return;
550         }
551
552         extract_token(username, &buf[4], 0, '|', sizeof username);
553         extract_token(password, &buf[4], 1, '|', sizeof password);
554         flags = extract_int(&buf[4], 2);
555         timescalled = extract_int(&buf[4], 3);
556         msgsposted = extract_int(&buf[4], 4);
557         axlevel = extract_int(&buf[4], 5);
558         usernum = extract_long(&buf[4], 6);
559         lastcall = extract_long(&buf[4], 7);
560         purgedays = extract_long(&buf[4], 8);
561
562         if (havebstr("edit_abe_button")) {
563                 display_edit_address_book_entry(username, usernum);
564                 return;
565         }
566
567         if (havebstr("delete_button")) {
568                 delete_user(username);
569                 return;
570         }
571
572         output_headers(1, 1, 2, 0, 0, 0);
573         wprintf("<div id=\"banner\">\n");
574         wprintf("<h1>");
575         wprintf(_("Edit user account: "));
576         escputs(username);
577         wprintf("</h1>");
578         wprintf("</div>");
579
580         wprintf("<div id=\"content\" class=\"service\">\n");
581
582         wprintf("<div class=\"fix_scrollbar_bug\">"
583                 "<table class=\"useredit_background\"><tr><td>\n");
584         wprintf("<form method=\"POST\" action=\"edituser\">\n"
585                 "<input type=\"hidden\" name=\"username\" value=\"");
586         escputs(username);
587         wprintf("\">\n");
588         wprintf("<input type=\"hidden\" name=\"is_new\" value=\"%d\">\n"
589                 "<input type=\"hidden\" name=\"usernum\" value=\"%ld\">\n",
590                 is_new, usernum);
591         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
592
593         wprintf("<input type=\"hidden\" name=\"flags\" value=\"%d\">\n", flags);
594
595         wprintf("<center><table>");
596
597         wprintf("<tr><td>");
598         wprintf(_("User name:"));
599         wprintf("</td><td>"
600                 "<input type=\"text\" name=\"newname\" value=\"");
601         escputs(username);
602         wprintf("\" maxlength=\"63\"></td></tr>\n");
603
604         wprintf("<tr><td>");
605         wprintf(_("Password"));
606         wprintf("</td><td>"
607                 "<input type=\"password\" name=\"password\" value=\"");
608         escputs(password);
609         wprintf("\" maxlength=\"20\"></td></tr>\n");
610
611         wprintf("<tr><td>");
612         wprintf(_("Permission to send Internet mail"));
613         wprintf("</td><td>");
614         wprintf("<input type=\"checkbox\" name=\"inetmail\" value=\"yes\" ");
615         if (flags & US_INTERNET) {
616                 wprintf("checked ");
617         }
618         wprintf("></td></tr>\n");
619
620         wprintf("<tr><td>");
621         wprintf(_("Number of logins"));
622         wprintf("</td><td>"
623                 "<input type=\"text\" name=\"timescalled\" value=\"");
624         wprintf("%d", timescalled);
625         wprintf("\" maxlength=\"6\"></td></tr>\n");
626
627         wprintf("<tr><td>");
628         wprintf(_("Messages submitted"));
629         wprintf("</td><td>"
630                 "<input type=\"text\" name=\"msgsposted\" value=\"");
631         wprintf("%d", msgsposted);
632         wprintf("\" maxlength=\"6\"></td></tr>\n");
633
634         wprintf("<tr><td>");
635         wprintf(_("Access level"));
636         wprintf("</td><td>"
637                 "<select name=\"axlevel\">\n");
638         for (i=0; i<7; ++i) {
639                 wprintf("<option ");
640                 if (axlevel == i) {
641                         wprintf("selected ");
642                 }
643                 wprintf("value=\"%d\">%d - %s</option>\n",
644                         i, i, axdefs[i]);
645         }
646         wprintf("</select></td></tr>\n");
647
648         wprintf("<tr><td>");
649         wprintf(_("User ID number"));
650         wprintf("</td><td>"
651                 "<input type=\"text\" name=\"usernum\" value=\"");
652         wprintf("%ld", usernum);
653         wprintf("\" maxlength=\"7\"></td></tr>\n");
654
655         now = time(NULL);
656         wprintf("<tr><td>");
657         wprintf(_("Date and time of last login"));
658         wprintf("</td><td>"
659                 "<select name=\"lastcall\">\n");
660
661         wprintf("<option selected value=\"%ld\">", lastcall);
662         escputs(asctime(localtime(&lastcall)));
663         wprintf("</option>\n");
664
665         wprintf("<option value=\"%ld\">", now);
666         escputs(asctime(localtime(&now)));
667         wprintf("</option>\n");
668
669         wprintf("</select></td></tr>");
670
671         wprintf("<tr><td>");
672         wprintf(_("Auto-purge after this many days"));
673         wprintf("</td><td>"
674                 "<input type=\"text\" name=\"purgedays\" value=\"");
675         wprintf("%d", purgedays);
676         wprintf("\" maxlength=\"5\"></td></tr>\n");
677
678         wprintf("</table>\n");
679
680         wprintf("<input type=\"submit\" name=\"ok_button\" value=\"%s\">\n"
681                 "&nbsp;"
682                 "<input type=\"submit\" name=\"cancel\" value=\"%s\">\n"
683                 "<br /><br /></form>\n", _("Save changes"), _("Cancel"));
684
685         wprintf("</center>\n");
686         wprintf("</td></tr></table></div>\n");
687         wDumpContent(1);
688
689 }
690
691
692 /**
693  * \brief do the backend operation of the user edit on the server
694  */
695 void edituser(void) {
696         char message[SIZ];
697         char buf[SIZ];
698         int is_new = 0;
699         unsigned int flags = 0;
700         char *username;
701
702         is_new = ibstr("is_new");
703         safestrncpy(message, "", sizeof message);
704         username = bstr("username");
705
706         if (!havebstr("ok_button")) {
707                 safestrncpy(message, _("Changes were not saved."), sizeof message);
708         }
709         
710         else {
711                 flags = ibstr("flags");
712                 if (yesbstr("inetmail")) {
713                         flags |= US_INTERNET;
714                 }
715                 else {
716                         flags &= ~US_INTERNET ;
717                 }
718
719                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
720                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
721                         serv_getln(buf, sizeof buf);
722                         if (buf[0] != '2') {
723                                 sprintf(&message[strlen(message)],
724                                         "<img src=\"static/error.gif\" align=center>"
725                                         "%s<br /><br />\n", &buf[4]);
726                         }
727                         else {
728                                 username = bstr("newname");
729                         }
730                 }
731
732                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
733                         username,
734                         bstr("password"),
735                         flags,
736                         bstr("timescalled"),
737                         bstr("msgsposted"),
738                         bstr("axlevel"),
739                         bstr("usernum"),
740                         bstr("lastcall"),
741                         bstr("purgedays")
742                 );
743                 serv_getln(buf, sizeof buf);
744                 if (buf[0] != '2') {
745                         sprintf(&message[strlen(message)],
746                                 "<img src=\"static/error.gif\" align=center>"
747                                 "%s<br /><br />\n", &buf[4]);
748                 }
749         }
750
751         /**
752          * If we are in the middle of creating a new user, move on to
753          * the vCard edit screen.
754          */
755         if (is_new) {
756                 display_edit_address_book_entry(username, lbstr("usernum") );
757         }
758         else {
759                 select_user_to_edit(message, username);
760         }
761 }
762
763 /*
764  * \brief burge a user 
765  * \param username the name of the user to remove
766  */
767 void delete_user(char *username) {
768         char buf[SIZ];
769         char message[SIZ];
770
771         serv_printf("ASUP %s|0|0|0|0|0|", username);
772         serv_getln(buf, sizeof buf);
773         if (buf[0] != '2') {
774                 sprintf(message,
775                         "<img src=\"static/error.gif\" align=center>"
776                         "%s<br /><br />\n", &buf[4]);
777         }
778         else {
779                 safestrncpy(message, "", sizeof message);
780         }
781         select_user_to_edit(message, bstr("username"));
782 }
783                 
784
785
786 /**
787  * \brief create a new user
788  * take the web environment username and create it on the citadel server
789  */
790 void create_user(void) {
791         char buf[SIZ];
792         char error_message[SIZ];
793         char username[SIZ];
794
795         safestrncpy(username, bstr("username"), sizeof username);
796
797         serv_printf("CREU %s", username);
798         serv_getln(buf, sizeof buf);
799
800         if (buf[0] == '2') {
801                 sprintf(WC->ImportantMessage, _("A new user has been created."));
802                 display_edituser(username, 1);
803         }
804         else if (!strncmp(buf, "570", 3)) {
805                 sprintf(error_message,
806                         "<img src=\"static/error.gif\" align=center>"
807                         "%s<br /><br />\n",
808                         _("You are attempting to create a new user from within Citadel "
809                         "while running in host based authentication mode.  In this mode, "
810                         "you must create new users on the host system, not within Citadel.")
811                 );
812                 select_user_to_edit(error_message, NULL);
813         }
814         else {
815                 sprintf(error_message,
816                         "<img src=\"static/error.gif\" align=center>"
817                         "%s<br /><br />\n", &buf[4]);
818                 select_user_to_edit(error_message, NULL);
819         }
820
821 }
822
823
824 void _select_user_to_edit(void){select_user_to_edit(NULL, NULL);}
825 void _display_edituser(void) {display_edituser(NULL, 0);}
826
827 void 
828 InitModule_USEREDIT
829 (void)
830 {
831         WebcitAddUrlHandler(HKEY("select_user_to_edit"), _select_user_to_edit, 0);
832         WebcitAddUrlHandler(HKEY("display_edituser"), _display_edituser, 0);
833         WebcitAddUrlHandler(HKEY("edituser"), edituser, 0);
834         WebcitAddUrlHandler(HKEY("create_user"), create_user, 0);
835
836         RegisterNamespace("USERLIST:USERNAME",  0, 1, tmplput_USERLIST_UserName, CTX_USERLIST);
837         RegisterNamespace("USERLIST:ACCLVLNO",  0, 0, tmplput_USERLIST_AccessLevelNo, CTX_USERLIST);
838         RegisterNamespace("USERLIST:ACCLVLSTR", 0, 0, tmplput_USERLIST_AccessLevelStr, CTX_USERLIST);
839         RegisterNamespace("USERLIST:UID",       0, 0, tmplput_USERLIST_UID, CTX_USERLIST);
840         RegisterNamespace("USERLIST:LASTLOGON", 0, 0, tmplput_USERLIST_LastLogon, CTX_USERLIST);
841         RegisterNamespace("USERLIST:NLOGONS",   0, 0, tmplput_USERLIST_nLogons, CTX_USERLIST);
842         RegisterNamespace("USERLIST:NPOSTS",    0, 0, tmplput_USERLIST_nPosts, CTX_USERLIST);
843
844         RegisterConditional(HKEY("COND:USERNAME"), 0, ConditionalUser, CTX_USERLIST);
845         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST);
846 }
847 /*@}*/