Back to index

citadel  8.12
routines2.c
Go to the documentation of this file.
00001 /*
00002  * More client-side support functions.
00003  * Unlike routines.c, some of these DO use global variables.
00004  *
00005  * Copyright (c) 1987-2012 by the citadel.org team
00006  *
00007  *  This program is open source software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License version 3.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  */
00015 
00016 #include <stdlib.h>
00017 #include <unistd.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 #include <stdio.h>
00022 #include <ctype.h>
00023 #include <string.h>
00024 #include <limits.h>
00025 
00026 #if TIME_WITH_SYS_TIME
00027 # include <sys/time.h>
00028 # include <time.h>
00029 #else
00030 # if HAVE_SYS_TIME_H
00031 #  include <sys/time.h>
00032 # else
00033 #  include <time.h>
00034 # endif
00035 #endif
00036 
00037 #include <signal.h>
00038 #include <pwd.h>
00039 #include <errno.h>
00040 #include <stdarg.h>
00041 #include <libcitadel.h>
00042 #include "sysdep.h"
00043 #include "citadel.h"
00044 #include "citadel_ipc.h"
00045 #include "citadel_decls.h"
00046 #include "routines2.h"
00047 #include "routines.h"
00048 #include "commands.h"
00049 #include "messages.h"
00050 #ifndef HAVE_SNPRINTF
00051 #include "snprintf.h"
00052 #endif
00053 #include "screen.h"
00054 
00055 /* work around solaris include files */
00056 #ifdef reg
00057 #undef reg
00058 #endif
00059 
00060 extern char temp[];
00061 extern char tempdir[];
00062 extern char *axdefs[8];
00063 extern long highest_msg_read;
00064 extern long maxmsgnum;
00065 extern unsigned room_flags;
00066 extern int screenwidth;
00067 
00068 
00069 /*
00070 int eopen(char *name, int mode)
00071 {
00072        int ret;
00073        ret = open(name, mode);
00074        if (ret < 0) {
00075               scr_printf("Cannot open file '%s', mode=%d, errno=%d\n",
00076                      name, mode, errno);
00077               interr(errno);
00078        }
00079        return (ret);
00080 }
00081 */
00082 
00083 
00084 int room_prompt(unsigned int qrflags)
00085 {                           /* return proper room prompt character */
00086        int a;
00087        a = '>';
00088        if (qrflags & QR_DIRECTORY)
00089               a = ']';
00090        if ((a == ']') && (qrflags & QR_NETWORK))
00091               a = '}';
00092        if ((a == '>') && (qrflags & QR_NETWORK))
00093               a = ')';
00094        return (a);
00095 }
00096 
00097 void entregis(CtdlIPC *ipc)
00098 {                           /* register with name and address */
00099 
00100        char buf[SIZ];
00101        char tmpname[30];
00102        char tmpaddr[25];
00103        char tmpcity[15];
00104        char tmpstate[3];
00105        char tmpzip[11];
00106        char tmpphone[15];
00107        char tmpemail[SIZ];
00108        char tmpcountry[32];
00109        char diruser[256];
00110        char dirnode[256];
00111        char holdemail[SIZ];
00112        char *reg = NULL;
00113        int ok = 0;
00114        int r;                      /* IPC response code */
00115 
00116        strcpy(tmpname, "");
00117        strcpy(tmpaddr, "");
00118        strcpy(tmpcity, "");
00119        strcpy(tmpstate, "");
00120        strcpy(tmpzip, "");
00121        strcpy(tmpphone, "");
00122        strcpy(tmpemail, "");
00123        strcpy(tmpcountry, "");
00124 
00125        r = CtdlIPCGetUserRegistration(ipc, NULL, &reg, buf);
00126        if (r / 100 == 1) {
00127               int a = 0;
00128 
00129               while (reg && !IsEmptyStr(reg)) {
00130 
00131                      extract_token(buf, reg, 0, '\n', sizeof buf);
00132                      remove_token(reg, 0, '\n');
00133 
00134                      if (a == 2)
00135                             safestrncpy(tmpname, buf, sizeof tmpname);
00136                      else if (a == 3)
00137                             safestrncpy(tmpaddr, buf, sizeof tmpaddr);
00138                      else if (a == 4)
00139                             safestrncpy(tmpcity, buf, sizeof tmpcity);
00140                      else if (a == 5)
00141                             safestrncpy(tmpstate, buf, sizeof tmpstate);
00142                      else if (a == 6)
00143                             safestrncpy(tmpzip, buf, sizeof tmpzip);
00144                      else if (a == 7)
00145                             safestrncpy(tmpphone, buf, sizeof tmpphone);
00146                      else if (a == 9)
00147                             safestrncpy(tmpemail, buf, sizeof tmpemail);
00148                      else if (a == 10)
00149                             safestrncpy(tmpcountry, buf, sizeof tmpcountry);
00150                      ++a;
00151               }
00152        }
00153        strprompt("REAL name", tmpname, 29);
00154        strprompt("Address", tmpaddr, 24);
00155        strprompt("City/town", tmpcity, 14);
00156        strprompt("State/province", tmpstate, 2);
00157        strprompt("ZIP/Postal Code", tmpzip, 10);
00158        strprompt("Country", tmpcountry, 31);
00159        strprompt("Telephone number", tmpphone, 14);
00160 
00161        do {
00162               ok = 1;
00163               safestrncpy(holdemail, tmpemail, sizeof holdemail);
00164               strprompt("Email address", tmpemail, 31);
00165               r = CtdlIPCDirectoryLookup(ipc, tmpemail, buf);
00166               if (r / 100 == 2) {
00167                      extract_token(diruser, buf, 0, '@', sizeof diruser);
00168                      extract_token(dirnode, buf, 1, '@', sizeof dirnode);
00169                      striplt(diruser);
00170                      striplt(dirnode);
00171                      if ((strcasecmp(diruser, fullname))
00172                         || (strcasecmp(dirnode, ipc->ServInfo.nodename))) {
00173                             scr_printf(
00174                                    "\nYou can't use %s as your address.\n",
00175                                    tmpemail);
00176                             scr_printf(
00177                                    "It is already in use by %s @ %s.\n",
00178                                    diruser, dirnode);
00179                             ok = 0;
00180                             safestrncpy(tmpemail, holdemail, sizeof tmpemail);
00181                      }
00182               }
00183        } while (ok == 0);
00184 
00185        /* now send the registration info back to the server */
00186        reg = (char *)realloc(reg, SIZ);
00187        if (reg) {
00188               sprintf(reg, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
00189                      tmpname, tmpaddr, tmpcity, tmpstate,
00190                      tmpzip, tmpphone, tmpemail, tmpcountry);
00191               r = CtdlIPCSetRegistration(ipc, reg, buf);
00192               if (r / 100 != 4)
00193                      scr_printf("%s\n", buf);
00194               free(reg);
00195        }
00196        scr_printf("\n");
00197 }
00198 
00199 void updatels(CtdlIPC *ipc)
00200 {                           /* make all messages old in current room */
00201        char buf[256];
00202        int r;                      /* IPC response code */
00203 
00204        r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ?  maxmsgnum : highest_msg_read, buf);
00205 
00206        if (r / 100 != 2)
00207               scr_printf("%s\n", buf);
00208 }
00209 
00210 /*
00211  * only make messages old in this room that have been read
00212  */
00213 void updatelsa(CtdlIPC *ipc)
00214 {
00215        char buf[256];
00216        int r;                      /* IPC response code */
00217 
00218        r = CtdlIPCSetLastRead(ipc, highest_msg_read, buf);
00219        if (r / 100 != 2)
00220               scr_printf("%s\n", &buf[4]);
00221 }
00222 
00223 
00224 /*
00225  * client-based uploads (for users with their own clientware)
00226  */
00227 void cli_upload(CtdlIPC *ipc)
00228 {
00229        char flnm[PATH_MAX];
00230        char desc[151];
00231        char buf[256];
00232        char tbuf[256];
00233        int r;        /* IPC response code */
00234        int a;
00235        int fd;
00236 
00237        if ((room_flags & QR_UPLOAD) == 0) {
00238               scr_printf("*** You cannot upload to this room.\n");
00239               return;
00240        }
00241        newprompt("File to be uploaded: ", flnm, 55);
00242        fd = open(flnm, O_RDONLY);
00243        if (fd < 0) {
00244               scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno));
00245               return;
00246        }
00247        scr_printf("Enter a description of this file:\n");
00248        newprompt(": ", desc, 75);
00249 
00250        /* Keep generating filenames in hope of finding a unique one */
00251        a = 0;
00252        while (a < 10) {
00253               /* basename of filename */
00254               strcpy(tbuf, flnm);
00255               if (haschar(tbuf, '/'))
00256                      extract_token(tbuf, flnm,
00257                             num_tokens(tbuf, '/') - 1,
00258                             '/', sizeof tbuf
00259                      );
00260               /* filename.1, filename.2, etc */
00261               if (a > 0) {
00262                      sprintf(&tbuf[strlen(tbuf)], ".%d", a);
00263               }
00264               /* Try upload */
00265               r = CtdlIPCFileUpload(ipc, tbuf, desc, flnm, progress, buf);
00266               if (r / 100 == 5 || r < 0)
00267                      scr_printf("%s\n", buf);
00268               else
00269                      break;
00270               ++a;
00271        }
00272        if (a > 0) scr_printf("Saved as '%s'\n", tbuf);
00273 }
00274 
00275 
00276 /*
00277  * Function used for various image upload commands
00278  */
00279 void cli_image_upload(CtdlIPC *ipc, char *keyname)
00280 {
00281        char flnm[PATH_MAX];
00282        char buf[256];
00283        int r;
00284 
00285        /* Can we upload this image? */
00286        r = CtdlIPCImageUpload(ipc, 0, NULL, keyname, NULL, buf);
00287        if (r / 100 != 2) {
00288               scr_printf("%s\n", buf);
00289               return;
00290        }
00291        newprompt("Image file to be uploaded: ", flnm, 55);
00292        r = CtdlIPCImageUpload(ipc, 1, flnm, keyname, progress, buf);
00293        if (r / 100 == 5) {
00294               scr_printf("%s\n", buf);
00295        } else if (r < 0) {
00296               scr_printf("Cannot upload '%s': %s\n", flnm, strerror(errno));
00297        }
00298        /* else upload succeeded */
00299 }
00300 
00301 
00302 /*
00303  * protocol-based uploads (Xmodem, Ymodem, Zmodem)
00304  */
00305 void upload(CtdlIPC *ipc, int c)
00306 {                           /* c = upload mode */
00307        char flnm[PATH_MAX];
00308        char desc[151];
00309        char buf[256];
00310        char tbuf[4096];
00311        int xfer_pid;
00312        int a, b;
00313        FILE *fp, *lsfp;
00314        int rv;
00315 
00316        if ((room_flags & QR_UPLOAD) == 0) {
00317               scr_printf("*** You cannot upload to this room.\n");
00318               return;
00319        }
00320        /* we don't need a filename when receiving batch y/z modem */
00321        if ((c == 2) || (c == 3))
00322               strcpy(flnm, "x");
00323        else
00324               newprompt("Enter filename: ", flnm, 15);
00325 
00326        for (a = 0; !IsEmptyStr(&flnm[a]); ++a)
00327               if ((flnm[a] == '/') || (flnm[a] == '\\') || (flnm[a] == '>')
00328                   || (flnm[a] == '?') || (flnm[a] == '*')
00329                   || (flnm[a] == ';') || (flnm[a] == '&'))
00330                      flnm[a] = '_';
00331 
00332        /* create a temporary directory... */
00333        if (mkdir(tempdir, 0700) != 0) {
00334               scr_printf("*** Could not create temporary directory %s: %s\n",
00335                      tempdir, strerror(errno));
00336               return;
00337        }
00338        /* now do the transfer ... in a separate process */
00339        xfer_pid = fork();
00340        if (xfer_pid == 0) {
00341               rv = chdir(tempdir);
00342               if (rv < 0) {
00343                      scr_printf("failed to change into %s Reason %s\nAborting now.\n", 
00344                                tempdir, 
00345                                strerror(errno));
00346                      nukedir(tempdir);
00347                      return;
00348               }
00349               switch (c) {
00350               case 0:
00351                      stty_ctdl(0);
00352                      scr_printf("Receiving %s - press Ctrl-D to end.\n", flnm);
00353                      fp = fopen(flnm, "w");
00354                      do {
00355                             b = inkey();
00356                             if (b == 13) {
00357                                    b = 10;
00358                             }
00359                             if (b != 4) {
00360                                    scr_printf("%c", b);
00361                                    putc(b, fp);
00362                             }
00363                      } while (b != 4);
00364                      fclose(fp);
00365                      exit(0);
00366               case 1:
00367                      stty_ctdl(3);
00368                      execlp("rx", "rx", flnm, NULL);
00369                      exit(1);
00370               case 2:
00371                      stty_ctdl(3);
00372                      execlp("rb", "rb", NULL);
00373                      exit(1);
00374               case 3:
00375                      stty_ctdl(3);
00376                      execlp("rz", "rz", NULL);
00377                      exit(1);
00378               }
00379        } else
00380               do {
00381                      b = ka_wait(&a);
00382               } while ((b != xfer_pid) && (b != (-1)));
00383        stty_ctdl(0);
00384 
00385        if (a != 0) {
00386               scr_printf("\r*** Transfer unsuccessful.\n");
00387               nukedir(tempdir);
00388               return;
00389        }
00390        scr_printf("\r*** Transfer successful.\n");
00391        snprintf(buf, sizeof buf, "cd %s; ls", tempdir);
00392        lsfp = popen(buf, "r");
00393        if (lsfp != NULL) {
00394               while (fgets(flnm, sizeof flnm, lsfp) != NULL) {
00395                      flnm[strlen(flnm) - 1] = 0; /* chop newline */
00396                      snprintf(buf, sizeof buf,
00397                              "Enter a short description of '%s':\n: ",
00398                              flnm);
00399                      newprompt(buf, desc, 150);
00400                      snprintf(buf, sizeof buf, "%s/%s", tempdir, flnm);
00401                      CtdlIPCFileUpload(ipc, flnm, desc, buf, progress, tbuf);
00402                      scr_printf("%s\n", tbuf);
00403               }
00404               pclose(lsfp);
00405        }
00406        nukedir(tempdir);
00407 }
00408 
00409 /* 
00410  * validate a user (returns 0 for successful validation, nonzero if quitting)
00411  */
00412 int val_user(CtdlIPC *ipc, char *user, int do_validate)
00413 {
00414        int a;
00415        char cmd[256];
00416        char buf[256];
00417        char *resp = NULL;
00418        int ax = 0;
00419        char answer[2];
00420        int r;                      /* IPC response code */
00421 
00422        scr_printf("\n");
00423        r = CtdlIPCGetUserRegistration(ipc, user, &resp, cmd);
00424        if (r / 100 == 1) {
00425               a = 0;
00426               do {
00427                      extract_token(buf, resp, 0, '\n', sizeof buf);
00428                      remove_token(resp, 0, '\n');
00429                      ++a;
00430                      if (a == 1)
00431                             scr_printf("User #%s - %s  ", buf, cmd);
00432                      if (a == 2)
00433                             scr_printf("PW: %s\n", (IsEmptyStr(buf) ? "<NOT SET>" : "<SET>") );
00434                      if (a == 3)
00435                             scr_printf("%s\n", buf);
00436                      if (a == 4)
00437                             scr_printf("%s\n", buf);
00438                      if (a == 5)
00439                             scr_printf("%s, ", buf);
00440                      if (a == 6)
00441                             scr_printf("%s ", buf);
00442                      if (a == 7)
00443                             scr_printf("%s\n", buf);
00444                      if (a == 8)
00445                             scr_printf("%s\n", buf);
00446                      if (a == 9)
00447                             ax = atoi(buf);
00448                      if (a == 10)
00449                             scr_printf("%s\n", buf);
00450                      if (a == 11)
00451                             scr_printf("%s\n", buf);
00452               } while (!IsEmptyStr(resp));
00453 
00454 /* TODODRW: discrepancy here. Parts of the code refer to axdefs[7] as the highest
00455  * but most of it limits it to axdefs[6].
00456  * Webcit limits to 6 as does the code here but there are 7 in axdefs.h
00457  */
00458               scr_printf("Current access level: %d (%s)\n", ax, axdefs[ax]);
00459        } else {
00460               scr_printf("%s\n%s\n", user, &cmd[4]);
00461        }
00462        if (resp) free(resp);
00463 
00464        if (do_validate) {
00465               /* now set the access level */
00466               while(1) {
00467                      sprintf(answer, "%d", ax);
00468                      strprompt("New access level (? for help, q to quit)",
00469                             answer, 1);
00470                      if ((answer[0] >= '0') && (answer[0] <= '6')) {
00471                             ax = atoi(answer);
00472                             r = CtdlIPCValidateUser(ipc, user, ax, cmd);
00473                             if (r / 100 != 2)
00474                             scr_printf("%s\n\n", cmd);
00475                             return(0);
00476                      }
00477                      if (tolower(answer[0]) == 'q') {
00478                             scr_printf("*** Aborted.\n\n");
00479                             return(1);
00480                      }
00481                      if (answer[0] == '?') {
00482                             scr_printf("Available access levels:\n");
00483                             for (a=0; a<7; ++a) {
00484                                    scr_printf("%d - %s\n",
00485                                           a, axdefs[a]);
00486                             }
00487                      }
00488               }
00489        }
00490        return(0);
00491 }
00492 
00493 
00494 void validate(CtdlIPC *ipc)
00495 {                           /* validate new users */
00496        char cmd[256];
00497        char buf[256];
00498        int finished = 0;
00499        int r;                      /* IPC response code */
00500 
00501        do {
00502               r = CtdlIPCNextUnvalidatedUser(ipc, cmd);
00503               if (r / 100 != 3)
00504                      finished = 1;
00505               if (r / 100 == 2)
00506                      scr_printf("%s\n", cmd);
00507               if (r / 100 == 3) {
00508                      extract_token(buf, cmd, 0, '|', sizeof buf);
00509                      if (val_user(ipc, buf, 1) != 0) finished = 1;
00510               }
00511        } while (finished == 0);
00512 }
00513 
00514 void subshell(void)
00515 {
00516        int a, b;
00517 
00518        stty_ctdl(SB_RESTORE);
00519        a = fork();
00520        if (a == 0) {
00521               signal(SIGINT, SIG_DFL);
00522               signal(SIGQUIT, SIG_DFL);
00523               execlp(getenv("SHELL"), getenv("SHELL"), NULL);
00524               scr_printf("Could not open a shell: %s\n", strerror(errno));
00525               exit(errno);
00526        }
00527        do {
00528               b = ka_wait(NULL);
00529        } while ((a != b) && (a != (-1)));
00530        stty_ctdl(0);
00531 }
00532 
00533 /*
00534  * <.A>ide <F>ile <D>elete command
00535  */
00536 void deletefile(CtdlIPC *ipc)
00537 {
00538        char filename[32];
00539        char buf[256];
00540 
00541        newprompt("Filename: ", filename, 31);
00542        if (IsEmptyStr(filename))
00543               return;
00544        CtdlIPCDeleteFile(ipc, filename, buf);
00545        scr_printf("%s\n", buf);
00546 }
00547 
00548 
00549 /*
00550  * <.A>ide <F>ile <M>ove command
00551  */
00552 void movefile(CtdlIPC *ipc)
00553 {
00554        char filename[64];
00555        char newroom[ROOMNAMELEN];
00556        char buf[256];
00557 
00558        newprompt("Filename: ", filename, 63);
00559        if (IsEmptyStr(filename))
00560               return;
00561        newprompt("Enter target room: ", newroom, ROOMNAMELEN - 1);
00562        CtdlIPCMoveFile(ipc, filename, newroom, buf);
00563        scr_printf("%s\n", buf);
00564 }
00565 
00566 
00567 /* 
00568  * list of users who have filled out a bio
00569  */
00570 void list_bio(CtdlIPC *ipc)
00571 {
00572        char buf[256];
00573        char *resp = NULL;
00574        int pos = 1;
00575        int r;               /* IPC response code */
00576 
00577        r = CtdlIPCListUsersWithBios(ipc, &resp, buf);
00578        if (r / 100 != 1) {
00579               scr_printf("%s\n", buf);
00580               return;
00581        }
00582        while (resp && !IsEmptyStr(resp)) {
00583               extract_token(buf, resp, 0, '\n', sizeof buf);
00584               remove_token(resp, 0, '\n');
00585               if ((pos + strlen(buf) + 5) > screenwidth) {
00586                      scr_printf("\n");
00587                      pos = 1;
00588               }
00589               scr_printf("%s, ", buf);
00590               pos = pos + strlen(buf) + 2;
00591        }
00592        scr_printf("%c%c  \n\n", 8, 8);
00593        if (resp) free(resp);
00594 }
00595 
00596 
00597 /*
00598  * read bio
00599  */
00600 void read_bio(CtdlIPC *ipc)
00601 {
00602        char who[256];
00603        char buf[256];
00604        char *resp = NULL;
00605        int r;               /* IPC response code */
00606 
00607        do {
00608               newprompt("Read bio for who ('?' for list) : ", who, 25);
00609               scr_printf("\n");
00610               if (!strcmp(who, "?"))
00611                      list_bio(ipc);
00612        } while (!strcmp(who, "?"));
00613 
00614        r = CtdlIPCGetBio(ipc, who, &resp, buf);
00615        if (r / 100 != 1) {
00616               scr_printf("%s\n", buf);
00617               return;
00618        }
00619        while (!IsEmptyStr(resp)) {
00620               extract_token(buf, resp, 0, '\n', sizeof buf);
00621               remove_token(resp, 0, '\n');
00622               scr_printf("%s\n", buf);
00623        }
00624        if (resp) free(resp);
00625 }
00626 
00627 
00628