bdd457dc24982236e8c66f29380c41118b7d6162
[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         int UID;
106         int AccessLevel;
107         int nLogons;
108         int nPosts;
109
110         StrBuf *UserName;
111         StrBuf *Passvoid;
112         time_t LastLogonT;
113         /* Just available for Single users to view: */
114         unsigned int Flags;
115         int DaysTillPurge;
116 } UserListEntry;
117
118
119 UserListEntry* NewUserListOneEntry(StrBuf *SerializedUser)
120 {
121         UserListEntry *ul;
122
123         if (StrLength(SerializedUser) < 8) 
124                 return NULL;
125
126         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
127         ul->UserName = NewStrBuf();
128         ul->Passvoid = NewStrBuf();
129
130         StrBufExtract_token(ul->UserName, SerializedUser, 0, '|');
131         StrBufExtract_token(ul->Passvoid, SerializedUser, 1, '|');
132         ul->Flags = (unsigned int)StrBufExtract_long(SerializedUser, 2, '|');
133         ul->nLogons = StrBufExtract_int(SerializedUser, 3, '|');
134         ul->nPosts = StrBufExtract_int(SerializedUser, 4, '|');
135         ul->AccessLevel = StrBufExtract_int(SerializedUser, 5, '|');
136         ul->UID = StrBufExtract_int(SerializedUser, 6, '|');
137         ul->LastLogonT = StrBufExtract_long(SerializedUser, 7, '|');
138         ul->DaysTillPurge = StrBufExtract_int(SerializedUser, 8, '|');
139         return ul;
140 }
141
142 void DeleteUserListEntry(void *vUserList)
143 {
144         UserListEntry *ul = (UserListEntry*) vUserList;
145         FreeStrBuf(&ul->UserName);
146         FreeStrBuf(&ul->Passvoid);
147         free(ul);
148 }
149
150 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
151 {
152         UserListEntry *ul;
153
154         if (StrLength(SerializedUserList) < 8) 
155                 return NULL;
156
157         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
158         ul->UserName = NewStrBuf();
159         ul->Passvoid = NewStrBuf();
160
161         StrBufExtract_token(ul->UserName, SerializedUserList, 0, '|');
162         ul->AccessLevel = StrBufExtract_int(SerializedUserList, 1, '|');
163         ul->UID = StrBufExtract_int(SerializedUserList, 2, '|');
164         ul->LastLogonT = StrBufExtract_long(SerializedUserList, 3, '|');
165         ul->nLogons = StrBufExtract_int(SerializedUserList, 4, '|');
166         ul->nPosts = StrBufExtract_int(SerializedUserList, 5, '|');
167         StrBufExtract_token(ul->Passvoid, SerializedUserList, 6, '|');
168         ul->Flags = 0;
169         ul->DaysTillPurge = -1;
170         return ul;
171 }
172
173 /*
174  * Sort by Username
175  */
176 int CompareUserListName(const void *vUser1, const void *vUser2)
177 {
178         UserListEntry *u1 = (UserListEntry*) vUser1;
179         UserListEntry *u2 = (UserListEntry*) vUser2;
180
181         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
182 }
183 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
184 {
185         UserListEntry *u1 = (UserListEntry*) vUser1;
186         UserListEntry *u2 = (UserListEntry*) vUser2;
187         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
188 }
189
190 /*
191  * Sort by AccessLevel
192  */
193 int CompareAccessLevel(const void *vUser1, const void *vUser2)
194 {
195         UserListEntry *u1 = (UserListEntry*) vUser1;
196         UserListEntry *u2 = (UserListEntry*) vUser2;
197
198         return (u1->AccessLevel > u2->AccessLevel);
199 }
200 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
201 {
202         UserListEntry *u1 = (UserListEntry*) vUser1;
203         UserListEntry *u2 = (UserListEntry*) vUser2;
204
205         return (u2->AccessLevel > u1->AccessLevel);
206 }
207
208
209 /*
210  * Sort by UID
211  */
212 int CompareUID(const void *vUser1, const void *vUser2)
213 {
214         UserListEntry *u1 = (UserListEntry*) vUser1;
215         UserListEntry *u2 = (UserListEntry*) vUser2;
216
217         return (u1->UID > u2->UID);
218 }
219 int CompareUIDRev(const void *vUser1, const void *vUser2)
220 {
221         UserListEntry *u1 = (UserListEntry*) vUser1;
222         UserListEntry *u2 = (UserListEntry*) vUser2;
223
224         return (u2->UID > u1->UID);
225 }
226
227 /*
228  * Sort By Date /// TODO!
229  */
230 int CompareLastLogon(const void *vUser1, const void *vUser2)
231 {
232         UserListEntry *u1 = (UserListEntry*) vUser1;
233         UserListEntry *u2 = (UserListEntry*) vUser2;
234
235         return (u1->LastLogonT > u2->LastLogonT);
236 }
237 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
238 {
239         UserListEntry *u1 = (UserListEntry*) vUser1;
240         UserListEntry *u2 = (UserListEntry*) vUser2;
241
242         return (u2->LastLogonT > u1->LastLogonT);
243 }
244
245 /*
246  * Sort By Number of Logons
247  */
248 int ComparenLogons(const void *vUser1, const void *vUser2)
249 {
250         UserListEntry *u1 = (UserListEntry*) vUser1;
251         UserListEntry *u2 = (UserListEntry*) vUser2;
252
253         return (u1->nLogons > u2->nLogons);
254 }
255 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
256 {
257         UserListEntry *u1 = (UserListEntry*) vUser1;
258         UserListEntry *u2 = (UserListEntry*) vUser2;
259
260         return (u2->nLogons > u1->nLogons);
261 }
262
263 /*
264  * Sort By Number of Posts
265  */
266 int ComparenPosts(const void *vUser1, const void *vUser2)
267 {
268         UserListEntry *u1 = (UserListEntry*) vUser1;
269         UserListEntry *u2 = (UserListEntry*) vUser2;
270
271         return (u1->nPosts > u2->nPosts);
272 }
273 int ComparenPostsRev(const void *vUser1, const void *vUser2)
274 {
275         UserListEntry *u1 = (UserListEntry*) vUser1;
276         UserListEntry *u2 = (UserListEntry*) vUser2;
277
278         return (u2->nPosts > u1->nPosts);
279 }
280
281
282 HashList *iterate_load_userlist(WCTemplateToken *Token)
283 {
284         HashList *Hash;
285         char buf[SIZ];
286         StrBuf *Buf;
287         UserListEntry* ul;
288         char nnn[64];
289         int nUsed;
290         int Order;
291         int len;
292         
293         serv_puts("LIST");
294         serv_getln(buf, sizeof buf);
295         if (buf[0] == '1') {
296                 Hash = NewHash(1, NULL);
297
298                 Buf = NewStrBuf();
299                 while ((len = StrBuf_ServGetln(Buf),
300                         strcmp(ChrPtr(Buf), "000"))) {
301                         ul = NewUserListEntry(Buf);
302                         if (ul == NULL)
303                                 continue;
304                         nUsed = GetCount(Hash);
305                         nUsed = snprintf(nnn, sizeof(nnn), "%d", nUsed+1);
306                         Put(Hash, nnn, nUsed, ul, DeleteUserListEntry); 
307                 }
308                 FreeStrBuf(&Buf);
309                 Order = ibstr("SortOrder");
310                 switch (ibstr("SortBy")){
311                 case 1: /*NAME*/
312                         SortByPayload(Hash, (Order)? 
313                                       CompareUserListName:
314                                       CompareUserListNameRev);
315                         break;
316                 case 2: /*AccessLevel*/
317                         SortByPayload(Hash, (Order)? 
318                                       CompareAccessLevel:
319                                       CompareAccessLevelRev);
320                         break;
321                 case 3: /*nLogons*/
322                         SortByPayload(Hash, (Order)? 
323                                       ComparenLogons:
324                                       ComparenLogonsRev);
325                         break;
326                 case 4: /*UID*/
327                         SortByPayload(Hash, (Order)? 
328                                       CompareUID:
329                                       CompareUIDRev);
330                         break;
331                 case 5: /*LastLogon*/
332                         SortByPayload(Hash, (Order)? 
333                                       CompareLastLogon:
334                                       CompareLastLogonRev);
335                         break;
336                 case 6: /* nLogons */
337                         SortByPayload(Hash, (Order)? 
338                                       ComparenLogons:
339                                       ComparenLogonsRev);
340                         break;
341                 case 7: /* Posts */
342                         SortByPayload(Hash, (Order)? 
343                                       ComparenPosts:
344                                       ComparenPostsRev);
345                         break;
346                 }
347                 return Hash;
348         }
349         return NULL;
350 }
351
352
353 void tmplput_USERLIST_UserName(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
354 {
355         UserListEntry *ul = (UserListEntry*) Context;
356 /// TODO: X
357         StrBufAppendBuf(Target, ul->UserName, 0);
358 }
359
360 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
361 {
362         UserListEntry *ul = (UserListEntry*) Context;
363
364         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
365 }
366
367 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
368 {
369         UserListEntry *ul = (UserListEntry*) Context;
370         
371         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
372 }
373
374 void tmplput_USERLIST_UID(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
375 {
376         UserListEntry *ul = (UserListEntry*) Context;
377
378         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
379 }
380
381 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
382 {
383         UserListEntry *ul = (UserListEntry*) Context;
384
385         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
386 }
387 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
388 {
389         UserListEntry *ul = (UserListEntry*) Context;
390         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
391 }
392
393 void tmplput_USERLIST_nLogons(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
394 {
395         UserListEntry *ul = (UserListEntry*) Context;
396
397         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
398 }
399
400 void tmplput_USERLIST_nPosts(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
401 {
402         UserListEntry *ul = (UserListEntry*) Context;
403
404         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
405 }
406
407 void tmplput_USERLIST_Flags(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
408 {
409         UserListEntry *ul = (UserListEntry*) Context;
410
411         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
412 }
413
414 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType)
415 {
416         UserListEntry *ul = (UserListEntry*) Context;
417
418         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
419 }
420
421 int ConditionalUser(WCTemplateToken *Tokens, void *Context, int ContextType)
422 {
423         UserListEntry *ul = (UserListEntry*) Context;
424         if (havebstr("usernum")) {
425                 return ibstr("usernum") == ul->UID;
426         }
427         else if (havebstr("username")) {
428                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
429         }
430         else 
431                 return 0;
432 }
433
434 int ConditionalFlagINetEmail(WCTemplateToken *Tokens, void *Context, int ContextType)
435 {
436         UserListEntry *ul = (UserListEntry*) Context;
437         return (ul->Flags & US_INTERNET) != 0;
438 }
439
440 int ConditionalUserAccess(WCTemplateToken *Tokens, void *Context, int ContextType)
441 {
442         UserListEntry *ul = (UserListEntry*) Context;
443
444         if (Tokens->Params[3]->Type == TYPE_LONG)
445                 return (Tokens->Params[3]->lvalue == ul->AccessLevel);
446         else
447                 return 0;
448 }
449
450 /**
451  * \brief Locate the message number of a user's vCard in the current room
452  * \param username the plaintext name of the user
453  * \param usernum the number of the user on the citadel server
454  * \return the message id of his vcard
455  */
456 long locate_user_vcard(char *username, long usernum) {
457         char buf[SIZ];
458         long vcard_msgnum = (-1L);
459         char content_type[SIZ];
460         char partnum[SIZ];
461         int already_tried_creating_one = 0;
462
463         struct stuff_t {
464                 struct stuff_t *next;
465                 long msgnum;
466         };
467
468         struct stuff_t *stuff = NULL;
469         struct stuff_t *ptr;
470
471 TRYAGAIN:
472         /** Search for the user's vCard */
473         serv_puts("MSGS ALL");
474         serv_getln(buf, sizeof buf);
475         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
476                 ptr = malloc(sizeof(struct stuff_t));
477                 ptr->msgnum = atol(buf);
478                 ptr->next = stuff;
479                 stuff = ptr;
480         }
481
482         /** Iterate through the message list looking for vCards */
483         while (stuff != NULL) {
484                 serv_printf("MSG0 %ld|2", stuff->msgnum);
485                 serv_getln(buf, sizeof buf);
486                 if (buf[0]=='1') {
487                         while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
488                                 if (!strncasecmp(buf, "part=", 5)) {
489                                         extract_token(partnum, &buf[5], 2, '|', sizeof partnum);
490                                         extract_token(content_type, &buf[5], 4, '|', sizeof content_type);
491                                         if (  (!strcasecmp(content_type, "text/x-vcard"))
492                                            || (!strcasecmp(content_type, "text/vcard")) ) {
493                                                 vcard_msgnum = stuff->msgnum;
494                                         }
495                                 }
496                         }
497                 }
498
499                 ptr = stuff->next;
500                 free(stuff);
501                 stuff = ptr;
502         }
503
504         /** If there's no vcard, create one */
505         if (vcard_msgnum < 0) if (already_tried_creating_one == 0) {
506                 already_tried_creating_one = 1;
507                 serv_puts("ENT0 1|||4");
508                 serv_getln(buf, sizeof buf);
509                 if (buf[0] == '4') {
510                         serv_puts("Content-type: text/x-vcard");
511                         serv_puts("");
512                         serv_puts("begin:vcard");
513                         serv_puts("end:vcard");
514                         serv_puts("000");
515                 }
516                 goto TRYAGAIN;
517         }
518
519         return(vcard_msgnum);
520 }
521
522
523 /**
524  * \brief Display the form for editing a user's address book entry
525  * \param username the name of the user
526  * \param usernum the citadel-uid of the user
527  */
528 void display_edit_address_book_entry(char *username, long usernum) {
529         char roomname[SIZ];
530         char buf[SIZ];
531         char error_message[SIZ];
532         long vcard_msgnum = (-1L);
533
534         /** Locate the user's config room, creating it if necessary */
535         sprintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
536         serv_printf("GOTO %s||1", roomname);
537         serv_getln(buf, sizeof buf);
538         if (buf[0] != '2') {
539                 serv_printf("CRE8 1|%s|5|||1|", roomname);
540                 serv_getln(buf, sizeof buf);
541                 serv_printf("GOTO %s||1", roomname);
542                 serv_getln(buf, sizeof buf);
543                 if (buf[0] != '2') {
544                         sprintf(error_message,
545                                 "<img src=\"static/error.gif\" align=center>"
546                                 "%s<br /><br />\n", &buf[4]);
547                         select_user_to_edit(error_message, username);
548                         return;
549                 }
550         }
551
552         vcard_msgnum = locate_user_vcard(username, usernum);
553
554         if (vcard_msgnum < 0) {
555                 sprintf(error_message,
556                         "<img src=\"static/error.gif\" align=center>%s<br /><br />\n",
557                         _("An error occurred while trying to create or edit this address book entry.")
558                 );
559                 select_user_to_edit(error_message, username);
560                 return;
561         }
562
563         do_edit_vcard(vcard_msgnum, "1", "select_user_to_edit", roomname);
564 }
565
566
567 void display_edituser(char *supplied_username, int is_new) {
568         UserListEntry* UL;
569         StrBuf *Buf;
570         char error_message[1024];
571         char MajorStatus;
572         char username[256];
573
574         if (supplied_username != NULL) {
575                 safestrncpy(username, supplied_username, sizeof username);
576         }
577         else {
578                 safestrncpy(username, bstr("username"), sizeof username);
579         }
580
581         Buf = NewStrBuf();
582         serv_printf("AGUP %s", username);
583         StrBuf_ServGetln(Buf);
584         MajorStatus = ChrPtr(Buf)[0];
585         StrBufCutLeft(Buf, 4);
586         if (MajorStatus != '2') {
587                 ///TODO ImportantMessage
588                 sprintf(error_message,
589                         "<img src=\"static/error.gif\" align=center>"
590                         "%s<br /><br />\n", ChrPtr(Buf));
591                 select_user_to_edit(error_message, username);
592                 FreeStrBuf(&Buf);
593                 return;
594         }
595         else {
596                 UL = NewUserListOneEntry(Buf);
597                 output_headers(1, 0, 0, 0, 1, 0);
598                 DoTemplate(HKEY("userlist_detailview"), NULL, (void*) UL, CTX_USERLIST);
599                 end_burst();
600                 
601         }
602         FreeStrBuf(&Buf);
603 }
604
605
606
607 /* *
608  * \brief Edit a user.  
609  * If supplied_username is null, look in the "username"
610  * web variable for the name of the user to edit.
611  * 
612  * If "is_new" is set to nonzero, this screen will set the web variables
613  * to send the user to the vCard editor next.
614  * \param supplied_username user to look up or NULL if to search in the environment
615  * \param is_new should we create the user?
616  * /
617 void display_edituser(char *supplied_username, int is_new) {
618         char buf[1024];
619         char error_message[1024];
620         time_t now;
621
622         char username[256];
623         char password[256];
624         unsigned int flags;
625         int timescalled;
626         int msgsposted;
627         int axlevel;
628         long usernum;
629         time_t lastcall;
630         int purgedays;
631         int i;
632
633         if (supplied_username != NULL) {
634                 safestrncpy(username, supplied_username, sizeof username);
635         }
636         else {
637                 safestrncpy(username, bstr("username"), sizeof username);
638         }
639
640         serv_printf("AGUP %s", username);
641         serv_getln(buf, sizeof buf);
642         if (buf[0] != '2') {
643                 sprintf(error_message,
644                         "<img src=\"static/error.gif\" align=center>"
645                         "%s<br /><br />\n", &buf[4]);
646                 select_user_to_edit(error_message, username);
647                 return;
648         }
649
650         extract_token(username, &buf[4], 0, '|', sizeof username);
651         extract_token(password, &buf[4], 1, '|', sizeof password);
652         flags = extract_int(&buf[4], 2);
653         timescalled = extract_int(&buf[4], 3);
654         msgsposted = extract_int(&buf[4], 4);
655         axlevel = extract_int(&buf[4], 5);
656         usernum = extract_long(&buf[4], 6);
657         lastcall = extract_long(&buf[4], 7);
658         purgedays = extract_long(&buf[4], 8);
659
660         if (havebstr("edit_abe_button")) {
661                 display_edit_address_book_entry(username, usernum);
662                 return;
663         }
664
665         if (havebstr("delete_button")) {
666                 delete_user(username);
667                 return;
668         }
669
670         output_headers(1, 1, 2, 0, 0, 0);
671         wprintf("<div id=\"banner\">\n");
672         wprintf("<h1>");
673         wprintf(_("Edit user account: "));
674         escputs(username);
675         wprintf("</h1>");
676         wprintf("</div>");
677
678         wprintf("<div id=\"content\" class=\"service\">\n");
679
680         wprintf("<div class=\"fix_scrollbar_bug\">"
681                 "<table class=\"useredit_background\"><tr><td>\n");
682         wprintf("<form method=\"POST\" action=\"edituser\">\n"
683                 "<input type=\"hidden\" name=\"username\" value=\"");
684         escputs(username);
685         wprintf("\">\n");
686         wprintf("<input type=\"hidden\" name=\"is_new\" value=\"%d\">\n"
687                 "<input type=\"hidden\" name=\"usernum\" value=\"%ld\">\n",
688                 is_new, usernum);
689         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
690
691         wprintf("<input type=\"hidden\" name=\"flags\" value=\"%d\">\n", flags);
692
693         wprintf("<center><table>");
694
695         wprintf("<tr><td>");
696         wprintf(_("User name:"));
697         wprintf("</td><td>"
698                 "<input type=\"text\" name=\"newname\" value=\"");
699         escputs(username);
700         wprintf("\" maxlength=\"63\"></td></tr>\n");
701
702         wprintf("<tr><td>");
703         wprintf(_("Password"));
704         wprintf("</td><td>"
705                 "<input type=\"password\" name=\"password\" value=\"");
706         escputs(password);
707         wprintf("\" maxlength=\"20\"></td></tr>\n");
708
709         wprintf("<tr><td>");
710         wprintf(_("Permission to send Internet mail"));
711         wprintf("</td><td>");
712         wprintf("<input type=\"checkbox\" name=\"inetmail\" value=\"yes\" ");
713         if (flags & US_INTERNET) {
714                 wprintf("checked ");
715         }
716         wprintf("></td></tr>\n");
717
718         wprintf("<tr><td>");
719         wprintf(_("Number of logins"));
720         wprintf("</td><td>"
721                 "<input type=\"text\" name=\"timescalled\" value=\"");
722         wprintf("%d", timescalled);
723         wprintf("\" maxlength=\"6\"></td></tr>\n");
724
725         wprintf("<tr><td>");
726         wprintf(_("Messages submitted"));
727         wprintf("</td><td>"
728                 "<input type=\"text\" name=\"msgsposted\" value=\"");
729         wprintf("%d", msgsposted);
730         wprintf("\" maxlength=\"6\"></td></tr>\n");
731
732         wprintf("<tr><td>");
733         wprintf(_("Access level"));
734         wprintf("</td><td>"
735                 "<select name=\"axlevel\">\n");
736         for (i=0; i<7; ++i) {
737                 wprintf("<option ");
738                 if (axlevel == i) {
739                         wprintf("selected ");
740                 }
741                 wprintf("value=\"%d\">%d - %s</option>\n",
742                         i, i, axdefs[i]);
743         }
744         wprintf("</select></td></tr>\n");
745
746         wprintf("<tr><td>");
747         wprintf(_("User ID number"));
748         wprintf("</td><td>"
749                 "<input type=\"text\" name=\"usernum\" value=\"");
750         wprintf("%ld", usernum);
751         wprintf("\" maxlength=\"7\"></td></tr>\n");
752
753         now = time(NULL);
754         wprintf("<tr><td>");
755         wprintf(_("Date and time of last login"));
756         wprintf("</td><td>"
757                 "<select name=\"lastcall\">\n");
758
759         wprintf("<option selected value=\"%ld\">", lastcall);
760         escputs(asctime(localtime(&lastcall)));
761         wprintf("</option>\n");
762
763         wprintf("<option value=\"%ld\">", now);
764         escputs(asctime(localtime(&now)));
765         wprintf("</option>\n");
766
767         wprintf("</select></td></tr>");
768
769         wprintf("<tr><td>");
770         wprintf(_("Auto-purge after this many days"));
771         wprintf("</td><td>"
772                 "<input type=\"text\" name=\"purgedays\" value=\"");
773         wprintf("%d", purgedays);
774         wprintf("\" maxlength=\"5\"></td></tr>\n");
775
776         wprintf("</table>\n");
777
778         wprintf("<input type=\"submit\" name=\"ok_button\" value=\"%s\">\n"
779                 "&nbsp;"
780                 "<input type=\"submit\" name=\"cancel\" value=\"%s\">\n"
781                 "<br /><br /></form>\n", _("Save changes"), _("Cancel"));
782
783         wprintf("</center>\n");
784         wprintf("</td></tr></table></div>\n");
785         wDumpContent(1);
786
787 }
788 */
789
790 /**
791  * \brief do the backend operation of the user edit on the server
792  */
793 void edituser(void) {
794         char message[SIZ];
795         char buf[SIZ];
796         int is_new = 0;
797         unsigned int flags = 0;
798         char *username;
799
800         is_new = ibstr("is_new");
801         safestrncpy(message, "", sizeof message);
802         username = bstr("username");
803
804         if (!havebstr("ok_button")) {
805                 safestrncpy(message, _("Changes were not saved."), sizeof message);
806         }
807         
808         else {
809                 flags = ibstr("flags");
810                 if (yesbstr("inetmail")) {
811                         flags |= US_INTERNET;
812                 }
813                 else {
814                         flags &= ~US_INTERNET ;
815                 }
816
817                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
818                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
819                         serv_getln(buf, sizeof buf);
820                         if (buf[0] != '2') {
821                                 sprintf(&message[strlen(message)],
822                                         "<img src=\"static/error.gif\" align=center>"
823                                         "%s<br /><br />\n", &buf[4]);
824                         }
825                         else {
826                                 username = bstr("newname");
827                         }
828                 }
829
830                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
831                         username,
832                         bstr("password"),
833                         flags,
834                         bstr("timescalled"),
835                         bstr("msgsposted"),
836                         bstr("axlevel"),
837                         bstr("usernum"),
838                         bstr("lastcall"),
839                         bstr("purgedays")
840                 );
841                 serv_getln(buf, sizeof buf);
842                 if (buf[0] != '2') {
843                         sprintf(&message[strlen(message)],
844                                 "<img src=\"static/error.gif\" align=center>"
845                                 "%s<br /><br />\n", &buf[4]);
846                 }
847         }
848
849         /**
850          * If we are in the middle of creating a new user, move on to
851          * the vCard edit screen.
852          */
853         if (is_new) {
854                 display_edit_address_book_entry(username, lbstr("usernum") );
855         }
856         else {
857                 select_user_to_edit(message, username);
858         }
859 }
860
861 /*
862  * \brief burge a user 
863  * \param username the name of the user to remove
864  */
865 void delete_user(char *username) {
866         char buf[SIZ];
867         char message[SIZ];
868
869         serv_printf("ASUP %s|0|0|0|0|0|", username);
870         serv_getln(buf, sizeof buf);
871         if (buf[0] != '2') {
872                 sprintf(message,
873                         "<img src=\"static/error.gif\" align=center>"
874                         "%s<br /><br />\n", &buf[4]);
875         }
876         else {
877                 safestrncpy(message, "", sizeof message);
878         }
879         select_user_to_edit(message, bstr("username"));
880 }
881                 
882
883
884 /**
885  * \brief create a new user
886  * take the web environment username and create it on the citadel server
887  */
888 void create_user(void) {
889         char buf[SIZ];
890         char error_message[SIZ];
891         char username[SIZ];
892
893         safestrncpy(username, bstr("username"), sizeof username);
894
895         serv_printf("CREU %s", username);
896         serv_getln(buf, sizeof buf);
897
898         if (buf[0] == '2') {
899                 sprintf(WC->ImportantMessage, _("A new user has been created."));
900                 display_edituser(username, 1);
901         }
902         else if (!strncmp(buf, "570", 3)) {
903                 sprintf(error_message,
904                         "<img src=\"static/error.gif\" align=center>"
905                         "%s<br /><br />\n",
906                         _("You are attempting to create a new user from within Citadel "
907                         "while running in host based authentication mode.  In this mode, "
908                         "you must create new users on the host system, not within Citadel.")
909                 );
910                 select_user_to_edit(error_message, NULL);
911         }
912         else {
913                 sprintf(error_message,
914                         "<img src=\"static/error.gif\" align=center>"
915                         "%s<br /><br />\n", &buf[4]);
916                 select_user_to_edit(error_message, NULL);
917         }
918
919 }
920
921
922 void _select_user_to_edit(void){select_user_to_edit(NULL, NULL);}
923 void _display_edituser(void) {display_edituser(NULL, 0);}
924
925 void 
926 InitModule_USEREDIT
927 (void)
928 {
929         WebcitAddUrlHandler(HKEY("select_user_to_edit"), _select_user_to_edit, 0);
930         WebcitAddUrlHandler(HKEY("display_edituser"), _display_edituser, 0);
931         WebcitAddUrlHandler(HKEY("edituser"), edituser, 0);
932         WebcitAddUrlHandler(HKEY("create_user"), create_user, 0);
933
934         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, CTX_USERLIST);
935         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, CTX_USERLIST);
936         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, CTX_USERLIST);
937         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, CTX_USERLIST);
938         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, CTX_USERLIST);
939         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, CTX_USERLIST);
940         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, CTX_USERLIST);
941         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, CTX_USERLIST);
942                                                     
943         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, CTX_USERLIST);
944         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, CTX_USERLIST);
945
946         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
947         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
948         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
949
950         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST);
951 }
952 /*@}*/