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