* useredit.c: added an "Delete user" button, because it was unintuitive
[citadel.git] / webcit / useredit.c
1 /*
2  * $Id$
3  *
4  * Administrative screen to add/change/delete user accounts
5  *
6  */
7
8
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include <sys/socket.h>
18 #include <sys/time.h>
19 #include <limits.h>
20 #include <netinet/in.h>
21 #include <netdb.h>
22 #include <string.h>
23 #include <pwd.h>
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <pthread.h>
27 #include <signal.h>
28 #include "webcit.h"
29 #include "webserver.h"
30
31
32
33
34
35 void select_user_to_edit(char *message, char *preselect)
36 {
37         char buf[SIZ];
38         char username[SIZ];
39
40         output_headers(1, 1, 2, 0, 1, 0, 0);
41         wprintf("<div id=\"banner\">\n");
42         wprintf("<table width=100%% border=0 bgcolor=#444455><tr>"
43                 "<td>"
44                 "<span class=\"titlebar\">"
45                 "<img src=\"/static/users-icon.gif\">"
46                 "Edit or delete users"
47                 "</span></td></tr></table>\n"
48                 "</div>\n<div id=\"content\">\n"
49         );
50
51         if (message != NULL) wprintf(message);
52
53         wprintf("<TABLE border=0 CELLSPACING=10><TR VALIGN=TOP><TD>\n");
54
55         svprintf("BOXTITLE", WCS_STRING, "Edit or Delete users");
56         do_template("beginbox");
57
58         wprintf("To edit an existing user account, select the user "
59                 "name from the list and click 'Edit'.<br /><br />");
60         
61         wprintf("<CENTER>"
62                 "<FORM METHOD=\"POST\" ACTION=\"/display_edituser\">\n");
63         wprintf("<SELECT NAME=\"username\" SIZE=10 STYLE=\"width:100%%\">\n");
64         serv_puts("LIST");
65         serv_gets(buf);
66         if (buf[0] == '1') {
67                 while (serv_gets(buf), strcmp(buf, "000")) {
68                         extract(username, buf, 0);
69                         wprintf("<OPTION");
70                         if (preselect != NULL)
71                            if (!strcasecmp(username, preselect))
72                               wprintf(" SELECTED");
73                         wprintf(">");
74                         escputs(username);
75                         wprintf("\n");
76                 }
77         }
78         wprintf("</SELECT><br />\n");
79
80         wprintf("<input type=submit name=sc value=\"Edit configuration\">");
81         wprintf("<input type=submit name=sc value=\"Edit address book entry\">");
82         wprintf("<input type=submit name=sc value=\"Delete user\" "
83                 "onClick=\"return confirm('Delete this user?');\">");
84         wprintf("</FORM></CENTER>\n");
85         do_template("endbox");
86
87         wprintf("</TD><TD>");
88
89         svprintf("BOXTITLE", WCS_STRING, "Add users");
90         do_template("beginbox");
91
92         wprintf("To create a new user account, enter the desired "
93                 "user name in the box below and click 'Create'.<br /><br />");
94
95         wprintf("<CENTER><FORM METHOD=\"POST\" ACTION=\"/create_user\">\n");
96         wprintf("New user: ");
97         wprintf("<input type=text name=username><br />\n"
98                 "<input type=submit value=\"Create\">"
99                 "</FORM></CENTER>\n");
100
101         do_template("endbox");
102         wprintf("</TD></TR></TABLE>\n");
103
104         wDumpContent(1);
105 }
106
107
108
109 /* 
110  * Locate the message number of a user's vCard in the current room
111  */
112 long locate_user_vcard(char *username, long usernum) {
113         char buf[SIZ];
114         long vcard_msgnum = (-1L);
115         char content_type[SIZ];
116         char partnum[SIZ];
117         int already_tried_creating_one = 0;
118
119         struct stuff_t {
120                 struct stuff_t *next;
121                 long msgnum;
122         };
123
124         struct stuff_t *stuff = NULL;
125         struct stuff_t *ptr;
126
127 TRYAGAIN:
128         /* Search for the user's vCard */
129         serv_puts("MSGS ALL");
130         serv_gets(buf);
131         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
132                 ptr = malloc(sizeof(struct stuff_t));
133                 ptr->msgnum = atol(buf);
134                 ptr->next = stuff;
135                 stuff = ptr;
136         }
137
138         /* Iterate through the message list looking for vCards */
139         while (stuff != NULL) {
140                 serv_printf("MSG0 %ld|2", stuff->msgnum);
141                 serv_gets(buf);
142                 if (buf[0]=='1') {
143                         while(serv_gets(buf), strcmp(buf, "000")) {
144                                 if (!strncasecmp(buf, "part=", 5)) {
145                                         extract(partnum, &buf[5], 2);
146                                         extract(content_type, &buf[5], 4);
147                                         if (!strcasecmp(content_type,
148                                            "text/x-vcard")) {
149                                                 vcard_msgnum = stuff->msgnum;
150                                         }
151                                 }
152                         }
153                 }
154
155                 ptr = stuff->next;
156                 free(stuff);
157                 stuff = ptr;
158         }
159
160         /* If there's no vcard, create one */
161         if (vcard_msgnum < 0) if (already_tried_creating_one == 0) {
162                 already_tried_creating_one = 1;
163                 serv_puts("ENT0 1|||4");
164                 serv_gets(buf);
165                 if (buf[0] == '4') {
166                         serv_puts("Content-type: text/x-vcard");
167                         serv_puts("");
168                         serv_puts("begin:vcard");
169                         serv_puts("end:vcard");
170                         serv_puts("000");
171                 }
172                 goto TRYAGAIN;
173         }
174
175         return(vcard_msgnum);
176 }
177
178
179 /* 
180  * Display the form for editing a user's address book entry
181  */
182 void display_edit_address_book_entry(char *username, long usernum) {
183         char roomname[SIZ];
184         char buf[SIZ];
185         char error_message[SIZ];
186         long vcard_msgnum = (-1L);
187
188         /* Locate the user's config room, creating it if necessary */
189         sprintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
190         serv_printf("GOTO %s||1", roomname);
191         serv_gets(buf);
192         if (buf[0] != '2') {
193                 serv_printf("CRE8 1|%s|5|||1|", roomname);
194                 serv_gets(buf);
195                 serv_printf("GOTO %s||1", roomname);
196                 serv_gets(buf);
197                 if (buf[0] != '2') {
198                         sprintf(error_message,
199                                 "<IMG SRC=\"static/error.gif\" ALIGN=CENTER>"
200                                 "%s<br /><br />\n", &buf[4]);
201                         select_user_to_edit(error_message, username);
202                         return;
203                 }
204         }
205
206         vcard_msgnum = locate_user_vcard(username, usernum);
207
208         if (vcard_msgnum < 0) {
209                 sprintf(error_message,
210                         "<IMG SRC=\"static/error.gif\" ALIGN=CENTER>"
211                         "Could not create/edit vCard"
212                         "<br /><br />\n"
213                 );
214                 select_user_to_edit(error_message, username);
215                 return;
216         }
217
218         do_edit_vcard(vcard_msgnum, "1", "/select_user_to_edit");
219 }
220
221
222
223
224 /*
225  * Edit a user.  If supplied_username is null, look in the "username"
226  * web variable for the name of the user to edit.
227  * 
228  * If "is_new" is set to nonzero, this screen will set the web variables
229  * to send the user to the vCard editor next.
230  */
231 void display_edituser(char *supplied_username, int is_new) {
232         char buf[SIZ];
233         char error_message[SIZ];
234         time_t now;
235
236         char username[SIZ];
237         char password[SIZ];
238         unsigned int flags;
239         int timescalled;
240         int msgsposted;
241         int axlevel;
242         long usernum;
243         time_t lastcall;
244         int purgedays;
245         int i;
246
247         if (supplied_username != NULL) {
248                 strcpy(username, supplied_username);
249         }
250         else {
251                 strcpy(username, bstr("username") );
252         }
253
254         serv_printf("AGUP %s", username);
255         serv_gets(buf);
256         if (buf[0] != '2') {
257                 sprintf(error_message,
258                         "<IMG SRC=\"static/error.gif\" ALIGN=CENTER>"
259                         "%s<br /><br />\n", &buf[4]);
260                 select_user_to_edit(error_message, username);
261                 return;
262         }
263
264         extract(username, &buf[4], 0);
265         extract(password, &buf[4], 1);
266         flags = extract_int(&buf[4], 2);
267         timescalled = extract_int(&buf[4], 3);
268         msgsposted = extract_int(&buf[4], 4);
269         axlevel = extract_int(&buf[4], 5);
270         usernum = extract_long(&buf[4], 6);
271         lastcall = extract_long(&buf[4], 7);
272         purgedays = extract_long(&buf[4], 8);
273
274         if (!strcmp(bstr("sc"), "Edit address book entry")) {
275                 display_edit_address_book_entry(username, usernum);
276                 return;
277         }
278
279         if (!strcmp(bstr("sc"), "Delete user")) {
280                 delete_user(username);
281                 return;
282         }
283
284         output_headers(1, 1, 2, 0, 0, 0, 0);
285         wprintf("<div id=\"banner\">\n");
286         wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#444455\"><TR><TD>");
287         wprintf("<SPAN CLASS=\"titlebar\">"
288                 "Edit user account: ");
289         escputs(username);
290         wprintf("</SPAN></TD></TR></TABLE>\n");
291         wprintf("</div>\n<div id=\"content\">\n");
292
293         do_template("beginbox_nt");
294         wprintf("<FORM METHOD=\"POST\" ACTION=\"/edituser\">\n"
295                 "<INPUT TYPE=\"hidden\" NAME=\"username\" VALUE=\"");
296         escputs(username);
297         wprintf("\">\n");
298         wprintf("<INPUT TYPE=\"hidden\" NAME=\"is_new\" VALUE=\"%d\">\n"
299                 "<INPUT TYPE=\"hidden\" NAME=\"usernum\" VALUE=\"%ld\">\n",
300                 is_new, usernum);
301
302         wprintf("<INPUT TYPE=\"hidden\" NAME=\"flags\" VALUE=\"%d\">\n", flags);
303
304         wprintf("<CENTER><TABLE>");
305
306         wprintf("<TR><TD>Password</TD><TD>"
307                 "<INPUT TYPE=\"password\" NAME=\"password\" VALUE=\"");
308         escputs(password);
309         wprintf("\" MAXLENGTH=\"20\"></TD></TR>\n");
310
311         wprintf("<TR><TD>Times logged in</TD><TD>"
312                 "<INPUT TYPE=\"text\" NAME=\"timescalled\" VALUE=\"");
313         wprintf("%d", timescalled);
314         wprintf("\" MAXLENGTH=\"6\"></TD></TR>\n");
315
316         wprintf("<TR><TD>Messages posted</TD><TD>"
317                 "<INPUT TYPE=\"text\" NAME=\"msgsposted\" VALUE=\"");
318         wprintf("%d", msgsposted);
319         wprintf("\" MAXLENGTH=\"6\"></TD></TR>\n");
320
321         wprintf("<TR><TD>Access level</TD><TD>"
322                 "<SELECT NAME=\"axlevel\">\n");
323         for (i=0; i<7; ++i) {
324                 wprintf("<OPTION ");
325                 if (axlevel == i) {
326                         wprintf("SELECTED ");
327                 }
328                 wprintf("VALUE=\"%d\">%d - %s</OPTION>\n",
329                         i, i, axdefs[i]);
330         }
331         wprintf("</SELECT></TD></TR>\n");
332
333         wprintf("<TR><TD>User ID number</TD><TD>"
334                 "<INPUT TYPE=\"text\" NAME=\"usernum\" VALUE=\"");
335         wprintf("%ld", usernum);
336         wprintf("\" MAXLENGTH=\"7\"></TD></TR>\n");
337
338         now = time(NULL);
339         wprintf("<TR><TD>Date/time of last login</TD><TD>"
340                 "<SELECT NAME=\"lastcall\">\n");
341
342         wprintf("<OPTION SELECTED VALUE=\"%ld\">", lastcall);
343         escputs(asctime(localtime(&lastcall)));
344         wprintf("</OPTION>\n");
345
346         wprintf("<OPTION VALUE=\"%ld\">", now);
347         escputs(asctime(localtime(&now)));
348         wprintf("</OPTION>\n");
349
350         wprintf("</SELECT></TD></TR>");
351
352         wprintf("<TR><TD>Auto-purge after days</TD><TD>"
353                 "<INPUT TYPE=\"text\" NAME=\"purgedays\" VALUE=\"");
354         wprintf("%d", purgedays);
355         wprintf("\" MAXLENGTH=\"5\"></TD></TR>\n");
356
357         wprintf("</TABLE>\n");
358
359         wprintf("<INPUT type=\"submit\" NAME=\"action\" VALUE=\"OK\">\n"
360                 "&nbsp;"
361                 "<INPUT type=\"submit\" NAME=\"action\" VALUE=\"Cancel\">\n"
362                 "<br /><br /></FORM>\n");
363
364         wprintf("</CENTER>\n");
365         do_template("endbox");
366
367         wDumpContent(1);
368
369 }
370
371
372
373 void edituser(void) {
374         char message[SIZ];
375         char buf[SIZ];
376         int is_new = 0;
377
378         is_new = atoi(bstr("is_new"));
379
380         if (strcasecmp(bstr("action"), "OK")) {
381                 strcpy(message, "Edit user cancelled.");
382         }
383
384         else {
385
386                 serv_printf("ASUP %s|%s|%s|%s|%s|%s|%s|%s|%s|",
387                         bstr("username"),
388                         bstr("password"),
389                         bstr("flags"),
390                         bstr("timescalled"),
391                         bstr("msgsposted"),
392                         bstr("axlevel"),
393                         bstr("usernum"),
394                         bstr("lastcall"),
395                         bstr("purgedays")
396                 );
397                 serv_gets(buf);
398                 if (buf[0] != '2') {
399                         sprintf(message,
400                                 "<IMG SRC=\"static/error.gif\" ALIGN=CENTER>"
401                                 "%s<br /><br />\n", &buf[4]);
402                 }
403                 else {
404                         strcpy(message, "");
405                 }
406         }
407
408         /* If we are in the middle of creating a new user, move on to
409          * the vCard edit screen.
410          */
411         if (is_new) {
412                 display_edit_address_book_entry( bstr("username"), atol(bstr("usernum")) );
413         }
414         else {
415                 select_user_to_edit(message, bstr("username"));
416         }
417 }
418
419
420 void delete_user(char *username) {
421         char buf[SIZ];
422         char message[SIZ];
423
424         serv_printf("ASUP %s|0|0|0|0|0|", username);
425         serv_gets(buf);
426         if (buf[0] != '2') {
427                 sprintf(message,
428                         "<IMG SRC=\"static/error.gif\" ALIGN=CENTER>"
429                         "%s<br /><br />\n", &buf[4]);
430         }
431         else {
432                 strcpy(message, "");
433         }
434         select_user_to_edit(message, bstr("username"));
435 }
436                 
437
438
439
440 void create_user(void) {
441         char buf[SIZ];
442         char error_message[SIZ];
443         char username[SIZ];
444
445         strcpy(username, bstr("username"));
446
447         serv_printf("CREU %s", username);
448         serv_gets(buf);
449
450         if (buf[0] == '2') {
451                 /* sprintf(error_message, "<b>User has been created.</b>");
452                 select_user_to_edit(error_message, username); */
453                 display_edituser(username, 1);
454         }
455         else {
456                 sprintf(error_message,
457                         "<IMG SRC=\"static/error.gif\" ALIGN=CENTER>"
458                         "%s<br /><br />\n", &buf[4]);
459                 select_user_to_edit(error_message, NULL);
460         }
461
462 }
463