* Fixed a multiselect bug in the mailbox view. Ctrl-click was selecting a message...
[citadel.git] / citadel / routines2.c
blobab8ec1c21a0a88e95981760e7f574126edb340ba
1 /* $Id$
3 * More client-side support functions.
4 * Unlike routines.c, some of these DO use global variables.
6 */
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <limits.h>
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # if HAVE_SYS_TIME_H
23 # include <sys/time.h>
24 # else
25 # include <time.h>
26 # endif
27 #endif
29 #include <signal.h>
30 #include <pwd.h>
31 #include <errno.h>
32 #include <stdarg.h>
33 #include <libcitadel.h>
34 #include "sysdep.h"
35 #include "citadel.h"
36 #include "citadel_ipc.h"
37 #include "citadel_decls.h"
38 #include "routines2.h"
39 #include "routines.h"
40 #include "commands.h"
41 #include "messages.h"
42 #ifndef HAVE_SNPRINTF
43 #include "snprintf.h"
44 #endif
45 #include "screen.h"
47 /* work around solaris include files */
48 #ifdef reg
49 #undef reg
50 #endif
52 extern char temp[];
53 extern char tempdir[];
54 extern char *axdefs[8];
55 extern long highest_msg_read;
56 extern long maxmsgnum;
57 extern unsigned room_flags;
58 extern int screenwidth;
62 int eopen(char *name, int mode)
64 int ret;
65 ret = open(name, mode);
66 if (ret < 0) {
67 err_printf("Cannot open file '%s', mode=%d, errno=%d\n",
68 name, mode, errno);
69 interr(errno);
71 return (ret);
76 int room_prompt(unsigned int qrflags)
77 { /* return proper room prompt character */
78 int a;
79 a = '>';
80 if (qrflags & QR_DIRECTORY)
81 a = ']';
82 if ((a == ']') && (qrflags & QR_NETWORK))
83 a = '}';
84 if ((a == '>') && (qrflags & QR_NETWORK))
85 a = ')';
86 return (a);
89 void entregis(CtdlIPC *ipc)
90 { /* register with name and address */
92 char buf[SIZ];
93 char tmpname[30];
94 char tmpaddr[25];
95 char tmpcity[15];
96 char tmpstate[3];
97 char tmpzip[11];
98 char tmpphone[15];
99 char tmpemail[SIZ];
100 char tmpcountry[32];
101 char diruser[256];
102 char dirnode[256];
103 char holdemail[SIZ];
104 char *reg = NULL;
105 int ok = 0;
106 int r; /* IPC response code */
108 strcpy(tmpname, "");
109 strcpy(tmpaddr, "");
110 strcpy(tmpcity, "");
111 strcpy(tmpstate, "");
112 strcpy(tmpzip, "");
113 strcpy(tmpphone, "");
114 strcpy(tmpemail, "");
115 strcpy(tmpcountry, "");
117 r = CtdlIPCGetUserRegistration(ipc, NULL, &reg, buf);
118 if (r / 100 == 1) {
119 int a = 0;
121 while (reg && !IsEmptyStr(reg)) {
123 extract_token(buf, reg, 0, '\n', sizeof buf);
124 remove_token(reg, 0, '\n');
126 if (a == 2)
127 safestrncpy(tmpname, buf, sizeof tmpname);
128 else if (a == 3)
129 safestrncpy(tmpaddr, buf, sizeof tmpaddr);
130 else if (a == 4)
131 safestrncpy(tmpcity, buf, sizeof tmpcity);
132 else if (a == 5)
133 safestrncpy(tmpstate, buf, sizeof tmpstate);
134 else if (a == 6)
135 safestrncpy(tmpzip, buf, sizeof tmpzip);
136 else if (a == 7)
137 safestrncpy(tmpphone, buf, sizeof tmpphone);
138 else if (a == 9)
139 safestrncpy(tmpemail, buf, sizeof tmpemail);
140 else if (a == 10)
141 safestrncpy(tmpcountry, buf, sizeof tmpcountry);
142 ++a;
145 strprompt("REAL name", tmpname, 29);
146 strprompt("Address", tmpaddr, 24);
147 strprompt("City/town", tmpcity, 14);
148 strprompt("State/province", tmpstate, 2);
149 strprompt("ZIP/Postal Code", tmpzip, 10);
150 strprompt("Country", tmpcountry, 31);
151 strprompt("Telephone number", tmpphone, 14);
153 do {
154 ok = 1;
155 safestrncpy(holdemail, tmpemail, sizeof holdemail);
156 strprompt("Email address", tmpemail, 31);
157 r = CtdlIPCDirectoryLookup(ipc, tmpemail, buf);
158 if (r / 100 == 2) {
159 extract_token(diruser, buf, 0, '@', sizeof diruser);
160 extract_token(dirnode, buf, 1, '@', sizeof dirnode);
161 striplt(diruser);
162 striplt(dirnode);
163 if ((strcasecmp(diruser, fullname))
164 || (strcasecmp(dirnode, ipc->ServInfo.nodename))) {
165 scr_printf(
166 "\nYou can't use %s as your address.\n",
167 tmpemail);
168 scr_printf(
169 "It is already in use by %s @ %s.\n",
170 diruser, dirnode);
171 ok = 0;
172 safestrncpy(tmpemail, holdemail, sizeof tmpemail);
175 } while (ok == 0);
177 /* now send the registration info back to the server */
178 reg = (char *)realloc(reg, SIZ);
179 if (reg) {
180 sprintf(reg, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
181 tmpname, tmpaddr, tmpcity, tmpstate,
182 tmpzip, tmpphone, tmpemail, tmpcountry);
183 r = CtdlIPCSetRegistration(ipc, reg, buf);
184 if (r / 100 != 4)
185 scr_printf("%s\n", buf);
186 free(reg);
188 scr_printf("\n");
191 void updatels(CtdlIPC *ipc)
192 { /* make all messages old in current room */
193 char buf[256];
194 int r; /* IPC response code */
196 if (rc_alt_semantics) {
197 if (maxmsgnum == 0 && highest_msg_read == 0) {
198 return;
200 r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ?
201 maxmsgnum : highest_msg_read, buf);
202 } else {
203 r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ?
204 maxmsgnum : highest_msg_read, buf);
205 /* r = CtdlIPCSetLastRead(ipc, maxmsgnum, buf); */
206 /* This is a quick-and-dirty fix to all msgs becoming new in Mail>.
207 * It will need to be rethought when messages.c is rewritten.
210 if (r / 100 != 2)
211 scr_printf("%s\n", buf);
215 * only make messages old in this room that have been read
217 void updatelsa(CtdlIPC *ipc)
219 char buf[256];
220 int r; /* IPC response code */
222 r = CtdlIPCSetLastRead(ipc, highest_msg_read, buf);
223 if (r / 100 != 2)
224 scr_printf("%s\n", &buf[4]);
229 * client-based uploads (for users with their own clientware)
231 void cli_upload(CtdlIPC *ipc)
233 char flnm[PATH_MAX];
234 char desc[151];
235 char buf[256];
236 char tbuf[256];
237 int r; /* IPC response code */
238 int a;
239 int fd;
241 if ((room_flags & QR_UPLOAD) == 0) {
242 scr_printf("*** You cannot upload to this room.\n");
243 return;
245 newprompt("File to be uploaded: ", flnm, 55);
246 fd = open(flnm, O_RDONLY);
247 if (fd < 0) {
248 scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno));
249 return;
251 scr_printf("Enter a description of this file:\n");
252 newprompt(": ", desc, 75);
254 /* Keep generating filenames in hope of finding a unique one */
255 a = 0;
256 while (a < 10) {
257 /* basename of filename */
258 strcpy(tbuf, flnm);
259 if (haschar(tbuf, '/'))
260 extract_token(tbuf, flnm,
261 num_tokens(tbuf, '/') - 1,
262 '/', sizeof tbuf
264 /* filename.1, filename.2, etc */
265 if (a > 0) {
266 sprintf(&tbuf[strlen(tbuf)], ".%d", a);
268 /* Try upload */
269 r = CtdlIPCFileUpload(ipc, tbuf, desc, flnm, progress, buf);
270 if (r / 100 == 5 || r < 0)
271 scr_printf("%s\n", buf);
272 else
273 break;
274 ++a;
276 if (a > 0) scr_printf("Saved as '%s'\n", tbuf);
281 * Function used for various image upload commands
283 void cli_image_upload(CtdlIPC *ipc, char *keyname)
285 char flnm[PATH_MAX];
286 char buf[256];
287 int r;
289 /* Can we upload this image? */
290 r = CtdlIPCImageUpload(ipc, 0, NULL, keyname, NULL, buf);
291 if (r / 100 != 2) {
292 err_printf("%s\n", buf);
293 return;
295 newprompt("Image file to be uploaded: ", flnm, 55);
296 r = CtdlIPCImageUpload(ipc, 1, flnm, keyname, progress, buf);
297 if (r / 100 == 5) {
298 err_printf("%s\n", buf);
299 } else if (r < 0) {
300 err_printf("Cannot upload '%s': %s\n", flnm, strerror(errno));
302 /* else upload succeeded */
307 * protocol-based uploads (Xmodem, Ymodem, Zmodem)
309 void upload(CtdlIPC *ipc, int c)
310 { /* c = upload mode */
311 char flnm[PATH_MAX];
312 char desc[151];
313 char buf[256];
314 char tbuf[4096];
315 int xfer_pid;
316 int a, b;
317 FILE *fp, *lsfp;
318 int r;
320 if ((room_flags & QR_UPLOAD) == 0) {
321 scr_printf("*** You cannot upload to this room.\n");
322 return;
324 /* we don't need a filename when receiving batch y/z modem */
325 if ((c == 2) || (c == 3))
326 strcpy(flnm, "x");
327 else
328 newprompt("Enter filename: ", flnm, 15);
330 for (a = 0; !IsEmptyStr(&flnm[a]); ++a)
331 if ((flnm[a] == '/') || (flnm[a] == '\\') || (flnm[a] == '>')
332 || (flnm[a] == '?') || (flnm[a] == '*')
333 || (flnm[a] == ';') || (flnm[a] == '&'))
334 flnm[a] = '_';
336 /* create a temporary directory... */
337 if (mkdir(tempdir, 0700) != 0) {
338 scr_printf("*** Could not create temporary directory %s: %s\n",
339 tempdir, strerror(errno));
340 return;
342 /* now do the transfer ... in a separate process */
343 xfer_pid = fork();
344 if (xfer_pid == 0) {
345 chdir(tempdir);
346 switch (c) {
347 case 0:
348 stty_ctdl(0);
349 scr_printf("Receiving %s - press Ctrl-D to end.\n", flnm);
350 fp = fopen(flnm, "w");
351 do {
352 b = inkey();
353 if (b == 13) {
354 b = 10;
356 if (b != 4) {
357 scr_printf("%c", b);
358 putc(b, fp);
360 } while (b != 4);
361 fclose(fp);
362 exit(0);
363 case 1:
364 screen_reset();
365 stty_ctdl(3);
366 execlp("rx", "rx", flnm, NULL);
367 exit(1);
368 case 2:
369 screen_reset();
370 stty_ctdl(3);
371 execlp("rb", "rb", NULL);
372 exit(1);
373 case 3:
374 screen_reset();
375 stty_ctdl(3);
376 execlp("rz", "rz", NULL);
377 exit(1);
379 } else
380 do {
381 b = ka_wait(&a);
382 } while ((b != xfer_pid) && (b != (-1)));
383 stty_ctdl(0);
384 screen_set();
386 if (a != 0) {
387 scr_printf("\r*** Transfer unsuccessful.\n");
388 nukedir(tempdir);
389 return;
391 scr_printf("\r*** Transfer successful.\n");
392 snprintf(buf, sizeof buf, "cd %s; ls", tempdir);
393 lsfp = popen(buf, "r");
394 if (lsfp != NULL) {
395 while (fgets(flnm, sizeof flnm, lsfp) != NULL) {
396 flnm[strlen(flnm) - 1] = 0; /* chop newline */
397 snprintf(buf, sizeof buf,
398 "Enter a short description of '%s':\n: ",
399 flnm);
400 newprompt(buf, desc, 150);
401 snprintf(buf, sizeof buf, "%s/%s", tempdir, flnm);
402 r = CtdlIPCFileUpload(ipc, flnm, desc, buf, progress, tbuf);
403 scr_printf("%s\n", tbuf);
405 pclose(lsfp);
407 nukedir(tempdir);
411 * validate a user (returns 0 for successful validation, nonzero if quitting)
413 int val_user(CtdlIPC *ipc, char *user, int do_validate)
415 int a;
416 char cmd[256];
417 char buf[256];
418 char *resp = NULL;
419 int ax = 0;
420 char answer[2];
421 int r; /* IPC response code */
423 scr_printf("\n");
424 r = CtdlIPCGetUserRegistration(ipc, user, &resp, cmd);
425 if (r / 100 == 1) {
426 a = 0;
427 do {
428 extract_token(buf, resp, 0, '\n', sizeof buf);
429 remove_token(resp, 0, '\n');
430 ++a;
431 if (a == 1)
432 scr_printf("User #%s - %s ", buf, cmd);
433 if (a == 2)
434 scr_printf("PW: %s\n", (IsEmptyStr(buf) ? "<NOT SET>" : "<SET>") );
435 if (a == 3)
436 scr_printf("%s\n", buf);
437 if (a == 4)
438 scr_printf("%s\n", buf);
439 if (a == 5)
440 scr_printf("%s, ", buf);
441 if (a == 6)
442 scr_printf("%s ", buf);
443 if (a == 7)
444 scr_printf("%s\n", buf);
445 if (a == 8)
446 scr_printf("%s\n", buf);
447 if (a == 9)
448 ax = atoi(buf);
449 if (a == 10)
450 scr_printf("%s\n", buf);
451 if (a == 11)
452 scr_printf("%s\n", buf);
453 } while (!IsEmptyStr(resp));
455 /* TODODRW: discrepancy here. Parts of the code refer to axdefs[7] as the highest
456 * but most of it limits it to axdefs[6].
457 * Webcit limits to 6 as does the code here but there are 7 in axdefs.h
459 scr_printf("Current access level: %d (%s)\n", ax, axdefs[ax]);
460 } else {
461 scr_printf("%s\n%s\n", user, &cmd[4]);
463 if (resp) free(resp);
465 if (do_validate) {
466 /* now set the access level */
467 while(1) {
468 sprintf(answer, "%d", ax);
469 strprompt("New access level (? for help, q to quit)",
470 answer, 1);
471 if ((answer[0] >= '0') && (answer[0] <= '6')) {
472 ax = atoi(answer);
473 r = CtdlIPCValidateUser(ipc, user, ax, cmd);
474 if (r / 100 != 2)
475 scr_printf("%s\n\n", cmd);
476 return(0);
478 if (tolower(answer[0]) == 'q') {
479 scr_printf("*** Aborted.\n\n");
480 return(1);
482 if (answer[0] == '?') {
483 scr_printf("Available access levels:\n");
484 for (a=0; a<7; ++a) {
485 scr_printf("%d - %s\n",
486 a, axdefs[a]);
491 return(0);
495 void validate(CtdlIPC *ipc)
496 { /* validate new users */
497 char cmd[256];
498 char buf[256];
499 int finished = 0;
500 int r; /* IPC response code */
502 do {
503 r = CtdlIPCNextUnvalidatedUser(ipc, cmd);
504 if (r / 100 != 3)
505 finished = 1;
506 if (r / 100 == 2)
507 scr_printf("%s\n", cmd);
508 if (r / 100 == 3) {
509 extract_token(buf, cmd, 0, '|', sizeof buf);
510 if (val_user(ipc, buf, 1) != 0) finished = 1;
512 } while (finished == 0);
515 void subshell(void)
517 int a, b;
519 screen_reset();
520 stty_ctdl(SB_RESTORE);
521 a = fork();
522 if (a == 0) {
523 signal(SIGINT, SIG_DFL);
524 signal(SIGQUIT, SIG_DFL);
525 execlp(getenv("SHELL"), getenv("SHELL"), NULL);
526 err_printf("Could not open a shell: %s\n", strerror(errno));
527 exit(errno);
529 do {
530 b = ka_wait(NULL);
531 } while ((a != b) && (a != (-1)));
532 stty_ctdl(0);
533 screen_set();
537 * <.A>ide <F>ile <D>elete command
539 void deletefile(CtdlIPC *ipc)
541 char filename[32];
542 char buf[256];
544 newprompt("Filename: ", filename, 31);
545 if (IsEmptyStr(filename))
546 return;
547 CtdlIPCDeleteFile(ipc, filename, buf);
548 err_printf("%s\n", buf);
553 * <.A>ide <F>ile <M>ove command
555 void movefile(CtdlIPC *ipc)
557 char filename[64];
558 char newroom[ROOMNAMELEN];
559 char buf[256];
561 newprompt("Filename: ", filename, 63);
562 if (IsEmptyStr(filename))
563 return;
564 newprompt("Enter target room: ", newroom, ROOMNAMELEN - 1);
565 CtdlIPCMoveFile(ipc, filename, newroom, buf);
566 err_printf("%s\n", buf);
571 * list of users who have filled out a bio
573 void list_bio(CtdlIPC *ipc)
575 char buf[256];
576 char *resp = NULL;
577 int pos = 1;
578 int r; /* IPC response code */
580 r = CtdlIPCListUsersWithBios(ipc, &resp, buf);
581 if (r / 100 != 1) {
582 pprintf("%s\n", buf);
583 return;
585 while (resp && !IsEmptyStr(resp)) {
586 extract_token(buf, resp, 0, '\n', sizeof buf);
587 remove_token(resp, 0, '\n');
588 if ((pos + strlen(buf) + 5) > screenwidth) {
589 pprintf("\n");
590 pos = 1;
592 pprintf("%s, ", buf);
593 pos = pos + strlen(buf) + 2;
595 pprintf("%c%c \n\n", 8, 8);
596 if (resp) free(resp);
601 * read bio
603 void read_bio(CtdlIPC *ipc)
605 char who[256];
606 char buf[256];
607 char *resp = NULL;
608 int r; /* IPC response code */
610 do {
611 newprompt("Read bio for who ('?' for list) : ", who, 25);
612 pprintf("\n");
613 if (!strcmp(who, "?"))
614 list_bio(ipc);
615 } while (!strcmp(who, "?"));
617 r = CtdlIPCGetBio(ipc, who, &resp, buf);
618 if (r / 100 != 1) {
619 pprintf("%s\n", buf);
620 return;
622 while (!IsEmptyStr(resp)) {
623 extract_token(buf, resp, 0, '\n', sizeof buf);
624 remove_token(resp, 0, '\n');
625 pprintf("%s\n", buf);
627 if (resp) free(resp);