Back to index

citadel  8.12
routines.c
Go to the documentation of this file.
00001 /*
00002  * Client-side support functions.
00003  *
00004  * Copyright (c) 1987-2012 by the citadel.org team
00005  *
00006  *  This program is open source software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License version 3.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  */
00014 
00015 #include "sysdep.h"
00016 #include <stdlib.h>
00017 #include <unistd.h>
00018 #include <fcntl.h>
00019 #include <stdio.h>
00020 #include <ctype.h>
00021 #include <string.h>
00022 #include <sys/types.h>
00023 #include <sys/ioctl.h>
00024 #include <pwd.h>
00025 #include <signal.h>
00026 #include <dirent.h>
00027 #include <errno.h>
00028 
00029 #if TIME_WITH_SYS_TIME
00030 # include <sys/time.h>
00031 # include <time.h>
00032 #else
00033 # if HAVE_SYS_TIME_H
00034 #  include <sys/time.h>
00035 # else
00036 #  include <time.h>
00037 # endif
00038 #endif
00039 
00040 #ifdef HAVE_LIMITS_H
00041 #include <limits.h>
00042 #endif
00043 #ifdef HAVE_UTMP_H
00044 #include <utmp.h>
00045 #endif
00046 #ifdef HAVE_UTMPX_H
00047 #include <utmpx.h>
00048 #endif
00049 
00050 #include <libcitadel.h>
00051 #include "citadel.h"
00052 #include "citadel_ipc.h"
00053 #include "screen.h"
00054 
00055 #ifndef HAVE_GETUTLINE
00056 struct utmp *getutline(struct utmp *ut);
00057 #endif
00058 
00059 #define ROUTINES_C
00060 
00061 #include "citadel.h"
00062 #include "routines.h"
00063 #include "commands.h"
00064 #include "citadel_decls.h"
00065 #include "routines2.h"
00066 #include "tuiconfig.h"
00067 
00068 #define IFAIDE if(axlevel>=AxAideU)
00069 #define IFNAIDE if (axlevel<AxAideU)
00070 
00071 extern unsigned userflags;
00072 //extern char *axdefs[8];
00073 extern char sigcaught;
00074 extern char rc_floor_mode;
00075 extern int rc_ansi_color;
00076 extern int rc_prompt_control;
00077 
00078 /* Destructive backspace */
00079 void back(int spaces) {
00080        int a;
00081        for (a=0; a<spaces; ++a) {
00082               scr_putc(8);
00083               scr_putc(32);
00084               scr_putc(8);
00085        }
00086 }
00087 
00088 /*
00089  * Edit or delete a user (cmd=25 to edit/create, 96 to delete)
00090  */
00091 void edituser(CtdlIPC *ipc, int cmd)
00092 {
00093        char buf[SIZ];
00094        char who[USERNAME_SIZE];
00095        char newname[USERNAME_SIZE];
00096        struct ctdluser *user = NULL;
00097        int newnow = 0;
00098        int r;                      /* IPC response code */
00099        int change_name = 0;
00100 
00101        strcpy(newname, "");
00102 
00103        newprompt("User name: ", who, 29);
00104        while ((r = CtdlIPCAideGetUserParameters(ipc, who, &user, buf)) / 100 != 2) {
00105               scr_printf("%s\n", buf);
00106               if (cmd == 25) {
00107                      scr_printf("Do you want to create this user? ");
00108                      if (yesno()) {
00109                             r = CtdlIPCCreateUser(ipc, who, 0, buf);
00110                             if (r / 100 == 2) {
00111                                    newnow = 1;
00112                                    continue;
00113                             }
00114                             scr_printf("%s\n", buf);
00115                      }
00116               }
00117               free(user);
00118               return;
00119        }
00120 
00121        if (cmd == 25) {
00122               val_user(ipc, user->fullname, 0); /* Display registration */
00123 
00124               if (!newnow) {
00125                      change_name = 1;
00126                      while (change_name == 1) {
00127                             if (boolprompt("Change name", 0)) {
00128                                    strprompt("New name", newname, USERNAME_SIZE-1);
00129                                    r = CtdlIPCRenameUser(ipc, user->fullname, newname, buf);
00130                                    if (r / 100 != 2) {
00131                                           scr_printf("%s\n", buf);
00132                                    }
00133                                    else {
00134                                           strcpy(user->fullname, newname);
00135                                           change_name = 0;
00136                                    }
00137                             }
00138                             else {
00139                                    change_name = 0;
00140                             }
00141                      }
00142               }
00143 
00144               if (newnow || boolprompt("Change password", 0)) {
00145                      strprompt("Password", user->password, -19);
00146               }
00147        
00148               user->axlevel = intprompt("Access level", user->axlevel, 0, 6);
00149               if (boolprompt("Permission to send Internet mail", (user->flags & US_INTERNET)))
00150                      user->flags |= US_INTERNET;
00151               else
00152                      user->flags &= ~US_INTERNET;
00153               if (boolprompt("Ask user to register again", !(user->flags & US_REGIS)))
00154                      user->flags &= ~US_REGIS;
00155               else
00156                      user->flags |= US_REGIS;
00157               user->timescalled = intprompt("Times called",
00158                             user->timescalled, 0, INT_MAX);
00159               user->posted = intprompt("Messages posted",
00160                                    user->posted, 0, INT_MAX);
00161               user->lastcall = boolprompt("Set last call to now", 0) ?
00162                                    time(NULL) : user->lastcall;
00163               user->USuserpurge = intprompt("Purge time (in days, 0 for system default",
00164                             user->USuserpurge, 0, INT_MAX);
00165        }
00166 
00167        if (cmd == 96) {
00168               scr_printf("Do you want to delete this user? ");
00169               if (!yesno()) {
00170                      free(user);
00171                      return;
00172               }
00173               user->axlevel = AxDeleted;
00174        }
00175 
00176        r = CtdlIPCAideSetUserParameters(ipc, user, buf);
00177        if (r / 100 != 2) {
00178               scr_printf("%s\n", buf);
00179        }
00180        free(user);
00181 }
00182 
00183 
00184 /* Display a prompt and flip a bit based on whether the user answers
00185  * yes or no.  Yes=1 and No=0, unless 'backwards' is set to a nonzero value
00186  * in which case No=1 and Yes=0.
00187  */
00188 int set_attr(CtdlIPC *ipc, unsigned int sval, char *prompt, unsigned int sbit, int backwards)
00189 {
00190        int a;
00191        int temp;
00192 
00193        temp = sval;
00194        color(DIM_WHITE);
00195        scr_printf("%50s ", prompt);
00196        color(DIM_MAGENTA);
00197        scr_printf("[");
00198        color(BRIGHT_MAGENTA);
00199 
00200        if (backwards) {
00201               scr_printf("%3s", ((temp&sbit) ? "No":"Yes"));
00202        }
00203        else {
00204               scr_printf("%3s", ((temp&sbit) ? "Yes":"No"));
00205        }
00206 
00207        color(DIM_MAGENTA);
00208        scr_printf("]? ");
00209        color(BRIGHT_CYAN);
00210        a = (temp & sbit);
00211        if (a != 0) a = 1;
00212        if (backwards) a = 1 - a;
00213        a = yesno_d(a);
00214        if (backwards) a = 1 - a;
00215        color(DIM_WHITE);
00216        temp = (temp|sbit);
00217        if (!a) temp = (temp^sbit);
00218        return(temp);
00219 }
00220 
00221 /*
00222  * modes are:  0 - .EC command, 1 - .EC for new user,
00223  *             2 - toggle Xpert mode  3 - toggle floor mode
00224  */
00225 void enter_config(CtdlIPC *ipc, int mode)
00226 {
00227        char buf[SIZ];
00228        struct ctdluser *user = NULL;
00229        int r;                      /* IPC response code */
00230 
00231        r = CtdlIPCGetConfig(ipc, &user, buf);
00232        if (r / 100 != 2) {
00233               scr_printf("%s\n", buf);
00234               free(user);
00235               return;
00236        }
00237 
00238        if (mode == 0 || mode == 1) {
00239 
00240               user->flags = set_attr(ipc, user->flags,
00241                                    "Are you an experienced Citadel user",
00242                                    US_EXPERT, 0);
00243               if ((user->flags & US_EXPERT) == 0 && mode == 1) {
00244                      free(user);
00245                      return;
00246               }
00247 
00248               user->flags = set_attr(
00249                      ipc,
00250                      user->flags,
00251                      "Print last old message on New message request",
00252                      US_LASTOLD,
00253                      0
00254               );
00255 
00256               user->flags = set_attr(
00257                      ipc,
00258                      user->flags,
00259                      "Prompt after each message",
00260                      US_NOPROMPT,
00261                      1
00262               );
00263 
00264               if ((user->flags & US_NOPROMPT) == 0) {
00265                      user->flags = set_attr(
00266                             ipc,
00267                             user->flags,
00268                             "Use 'disappearing' prompts",
00269                             US_DISAPPEAR,
00270                             0
00271                      );
00272               }
00273 
00274               user->flags = set_attr(
00275                      ipc,
00276                      user->flags,
00277                      "Pause after each screenful of text",
00278                      US_PAGINATOR,
00279                      0
00280               );
00281 
00282               if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) {
00283                      user->flags = set_attr(
00284                             ipc,
00285                             user->flags,
00286                             "<N>ext and <S>top work at paginator prompt",
00287                             US_PROMPTCTL,
00288                             0
00289                      );
00290               }
00291 
00292               if (rc_floor_mode == RC_DEFAULT) {
00293                      user->flags = set_attr(
00294                             ipc,
00295                             user->flags,
00296                             "View rooms by floor",
00297                             US_FLOORS,
00298                             0
00299                      );
00300               }
00301 
00302               if (rc_ansi_color == 3) {
00303                      user->flags = set_attr(
00304                             ipc,
00305                             user->flags,
00306                             "Enable color support",
00307                             US_COLOR,
00308                             0
00309                      );
00310               }
00311 
00312               if ((user->flags & US_EXPERT) == 0) {
00313                      formout(ipc, "unlisted");
00314               }
00315 
00316               user->flags = set_attr(
00317                      ipc,
00318                      user->flags,
00319                      "Be unlisted in userlog",
00320                      US_UNLISTED,
00321                      0
00322               );
00323 
00324               if (!IsEmptyStr(editor_path)) {
00325                      user->flags = set_attr(
00326                             ipc,
00327                             user->flags,
00328                             "Always enter messages with the full-screen editor",
00329                             US_EXTEDIT,
00330                             0
00331                      );
00332               }
00333 
00334        }
00335 
00336        if (mode == 2) {
00337               if (user->flags & US_EXPERT) {
00338                      user->flags ^= US_EXPERT;
00339                      scr_printf("Expert mode now OFF\n");
00340               } else {
00341                      user->flags |= US_EXPERT;
00342                      scr_printf("Expert mode now ON\n");
00343               }
00344        }
00345 
00346        if (mode == 3) {
00347               if (user->flags & US_FLOORS) {
00348                      user->flags ^= US_FLOORS;
00349                      scr_printf("Floor mode now OFF\n");
00350               } else {
00351                      user->flags |= US_FLOORS;
00352                      scr_printf("Floor mode now ON\n");
00353               }
00354        }
00355 
00356        r = CtdlIPCSetConfig(ipc, user, buf);
00357        if (r / 100 != 2) scr_printf("%s\n", buf);
00358        userflags = user->flags;
00359        free(user);
00360 }
00361 
00362 /*
00363  * getstring()  -  get a line of text from a file
00364  *               ignores lines beginning with "#"
00365  */
00366 int getstring(FILE *fp, char *string)
00367 {
00368        int a,c;
00369        do {
00370               strcpy(string,"");
00371               a=0;
00372               do {
00373                      c=getc(fp);
00374                      if (c<0) {
00375                             string[a]=0;
00376                             return(-1);
00377                      }
00378                      string[a++]=c;
00379               } while(c!=10);
00380                      string[a-1]=0;
00381        } while(string[0]=='#');
00382        return(strlen(string));
00383 }
00384 
00385 
00386 /* Searches for patn in search string */
00387 int pattern(char *search, char *patn) {
00388        int a,b,len;
00389        
00390        len = strlen(patn);
00391        for (a=0; !IsEmptyStr(&search[a]); ++a) {
00392               b=strncasecmp(&search[a],patn,len);
00393               if (b==0) return(b);
00394        }
00395        return(-1);
00396 }
00397 
00398 
00399 void strproc(char *string)
00400 {
00401        int a;
00402 
00403        if (IsEmptyStr(string)) return;
00404 
00405        /* Convert non-printable characters to blanks */
00406        for (a=0; !IsEmptyStr(&string[a]); ++a) {
00407               if (string[a]<32) string[a]=32;
00408               if (string[a]>126) string[a]=32;
00409        }
00410 
00411        /* Remove leading and trailing blanks */
00412        while(string[0]<33) strcpy(string,&string[1]);
00413        while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
00414 
00415        /* Remove double blanks */
00416        for (a=0; a<strlen(string); ++a) {
00417               if ((string[a]==32)&&(string[a+1]==32)) {
00418                      strcpy(&string[a],&string[a+1]);
00419                      a=0;
00420               }
00421        }
00422 
00423        /* remove characters which would interfere with the network */
00424        for (a=0; a<strlen(string); ++a) {
00425               if (string[a]=='!') strcpy(&string[a],&string[a+1]);
00426               if (string[a]=='@') strcpy(&string[a],&string[a+1]);
00427               if (string[a]=='_') strcpy(&string[a],&string[a+1]);
00428               if (string[a]==',') strcpy(&string[a],&string[a+1]);
00429               if (string[a]=='%') strcpy(&string[a],&string[a+1]);
00430               if (string[a]=='|') strcpy(&string[a],&string[a+1]);
00431        }
00432 
00433 }
00434 
00435 
00436 #ifndef HAVE_STRERROR
00437 /*
00438  * replacement strerror() for systems that don't have it
00439  */
00440 char *strerror(int e)
00441 {
00442        static char buf[128];
00443 
00444        snprintf(buf, sizeof buf, "errno = %d",e);
00445        return(buf);
00446 }
00447 #endif
00448 
00449 
00450 void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax)
00451 {
00452        static char dots[] =
00453               "**************************************************";
00454        char dots_printed[51];
00455        char fmt[42];
00456        unsigned long a;
00457 
00458        if (curr >= cmax) {
00459               scr_printf("\r%79s\r","");
00460        } else {
00461               /* a will be range 0-50 rather than 0-100 */
00462               a=(curr * 50) / cmax;
00463               sprintf(fmt, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a);
00464               strncpy(dots_printed, dots, a);
00465               dots_printed[a] = 0;
00466               scr_printf(fmt, dots_printed, "",
00467                             curr * 100 / cmax, curr, cmax);
00468               scr_flush();
00469        }
00470 }
00471 
00472 
00473 /*
00474  * NOT the same locate_host() in locate_host.c.  This one just does a
00475  * 'who am i' to try to discover where the user is...
00476  */
00477 void locate_host(CtdlIPC* ipc, char *hbuf)
00478 {
00479 #ifndef HAVE_UTMP_H
00480        char buf[SIZ];
00481        FILE *who;
00482        int a,b;
00483 
00484        who = (FILE *)popen("who am i","r");
00485        if (who==NULL) {
00486               strcpy(hbuf, ipc->ServInfo.fqdn);
00487               return;       
00488        }
00489        fgets(buf,sizeof buf,who);
00490        pclose(who);
00491 
00492        b = 0;
00493        for (a=0; !IsEmptyStr(&buf[a]); ++a) {
00494               if ((buf[a]=='(')||(buf[a]==')')) ++b;
00495        }
00496        if (b<2) {
00497               strcpy(hbuf, ipc->ServInfo.fqdn);
00498               return;
00499        }
00500 
00501        for (a=0; a<strlen(buf); ++a) {
00502               if (buf[a]=='(') {
00503                      strcpy(buf,&buf[a+1]);
00504               }
00505        }
00506        for (a=0; a<strlen(buf); ++a) {
00507               if (buf[a]==')') buf[a] = 0;
00508        }
00509 
00510        if (IsEmptyStr(buf)) strcpy(hbuf, ipc->ServInfo.fqdn);
00511        else strncpy(hbuf,buf,24);
00512 #else
00513        char *tty = ttyname(0);
00514 #ifdef HAVE_GETUTXLINE
00515        struct utmpx ut, *put;
00516 #else
00517        struct utmp ut, *put;
00518 #endif
00519 
00520        if (tty == NULL) {
00521            fail:
00522               safestrncpy(hbuf, ipc->ServInfo.fqdn, 24);
00523               return;
00524        }
00525 
00526        if (strncmp(tty, "/dev/", 5))
00527               goto fail;
00528 
00529        safestrncpy(ut.ut_line, &tty[5], sizeof ut.ut_line);
00530 
00531 #ifdef HAVE_GETUTXLINE /* Solaris uses this */
00532        if ((put = getutxline(&ut)) == NULL)
00533 #else
00534        if ((put = getutline(&ut)) == NULL)
00535 #endif
00536               goto fail;
00537 
00538 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
00539        if (put->ut_type == USER_PROCESS) {
00540 #endif
00541 #if defined(HAVE_UT_HOST) || defined(HAVE_GETUTXLINE)
00542               if (*put->ut_host)
00543                      safestrncpy(hbuf, put->ut_host, 24);
00544               else
00545 #endif
00546                      safestrncpy(hbuf, put->ut_line, 24);
00547 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
00548        }
00549        else goto fail;
00550 #endif
00551 #endif /* HAVE_UTMP_H */
00552 }
00553 
00554 /*
00555  * miscellaneous server commands (testing, etc.)
00556  */
00557 void misc_server_cmd(CtdlIPC *ipc, char *cmd) {
00558        char buf[SIZ];
00559 
00560        CtdlIPC_chat_send(ipc, cmd);
00561        CtdlIPC_chat_recv(ipc, buf);
00562        scr_printf("%s\n",buf);
00563        if (buf[0]=='1') {
00564               set_keepalives(KA_HALF);
00565               while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf,"000")) {
00566                      scr_printf("%s\n",buf);
00567               }
00568               set_keepalives(KA_YES);
00569               return;
00570        }
00571        if (buf[0]=='4') {
00572               do {
00573                      newprompt("> ",buf,255);
00574                      CtdlIPC_chat_send(ipc, buf);
00575               } while(strcmp(buf,"000"));
00576               return;
00577        }
00578 }
00579 
00580 
00581 /*
00582  * compute the checksum of a file
00583  */
00584 int file_checksum(char *filename)
00585 {
00586        int cksum = 0;
00587        int ch;
00588        FILE *fp;
00589 
00590        fp = fopen(filename,"r");
00591        if (fp == NULL) return(0);
00592 
00593        /* yes, this algorithm may allow cksum to overflow, but that's ok
00594         * as long as it overflows consistently, which it will.
00595         */
00596        while (ch=getc(fp), ch>=0) {
00597               cksum = (cksum + ch);
00598        }
00599 
00600        fclose(fp);
00601        return(cksum);
00602 }
00603 
00604 /*
00605  * nuke a directory and its contents
00606  */
00607 int nukedir(char *dirname)
00608 {
00609        DIR *dp;
00610        struct dirent *d;
00611        char filename[SIZ];
00612 
00613        dp = opendir(dirname);
00614        if (dp == NULL) {
00615               return(errno);
00616        }
00617 
00618        while (d = readdir(dp), d != NULL) {
00619               snprintf(filename, sizeof filename, "%s/%s",
00620                      dirname, d->d_name);
00621               unlink(filename);
00622        }
00623 
00624        closedir(dp);
00625        return(rmdir(dirname));
00626 }