]> code.citadel.org Git - citadel.git/blobdiff - citadel/citadel.c
Patches submitted by matt:
[citadel.git] / citadel / citadel.c
index 6d7b569cf93cde7e419e123dee822fb89b987c5f..383ba66322ad3d3bd98da675e68b1506ee1ef981 100644 (file)
@@ -50,6 +50,7 @@
 #include "snprintf.h"
 #endif
 #include "screen.h"
+#include "citadel_dirs.h"
 
 #include "md5.h"
 
@@ -58,6 +59,8 @@
 #define IFAIDE if (axlevel>=6)
 #define IFNAIDE if (axlevel<6)
 
+int rordercmp(struct ctdlroomlisting *r1, struct ctdlroomlisting *r2);
+
 struct march *march = NULL;
 
 /* globals associated with the client program */
@@ -300,7 +303,7 @@ void remove_march(char *roomname, int floornum)
  * Locate the room on the march list which we most want to go to.  Each room
  * is measured given a "weight" of preference based on various factors.
  */
-char *pop_march(int desired_floor)
+char *pop_march(int desired_floor, struct march *_march)
 {
        static char TheRoom[ROOMNAMELEN];
        int TheFloor = 0;
@@ -310,10 +313,10 @@ char *pop_march(int desired_floor)
        struct march *mptr = NULL;
 
        strcpy(TheRoom, "_BASEROOM_");
-       if (march == NULL)
+       if (_march == NULL)
                return (TheRoom);
 
-       for (mptr = march; mptr != NULL; mptr = mptr->next) {
+       for (mptr = _march; mptr != NULL; mptr = mptr->next) {
                weight = 0;
                if ((strcasecmp(mptr->march_name, "_BASEROOM_")))
                        weight = weight + 10000;
@@ -528,7 +531,7 @@ void gotonext(CtdlIPC *ipc)
                remove_march(room_name, 0);
        }
        if (march != NULL) {
-               strcpy(next_room, pop_march(curr_floor));
+               strcpy(next_room, pop_march(curr_floor, march));
        } else {
                strcpy(next_room, "_BASEROOM_");
        }
@@ -644,9 +647,9 @@ void gotofloor(CtdlIPC *ipc, char *towhere, int mode)
        if (r / 100 == 1) {
                struct march *tmp = mptr;
 
-               /* TODO: room order is being ignored? */
+               /*. . . according to room order */
                if (mptr)
-                       strncpy(targ, mptr->march_name, ROOMNAMELEN);
+           strcpy(targ, pop_march(tofloor, mptr));
                while (mptr) {
                        tmp = mptr->next;
                        free(mptr);
@@ -665,10 +668,10 @@ void gotofloor(CtdlIPC *ipc, char *towhere, int mode)
        r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, tofloor, &mptr, buf);
        if (r / 100 == 1) {
                struct march *tmp = mptr;
-
-               /* TODO: room order is being ignored? */
+               
+        /*. . . according to room order */
                if (mptr)
-                       strncpy(targ, mptr->march_name, ROOMNAMELEN);
+                       strcpy(targ, pop_march(tofloor, mptr));
                while (mptr) {
                        tmp = mptr->next;
                        free(mptr);
@@ -682,6 +685,300 @@ void gotofloor(CtdlIPC *ipc, char *towhere, int mode)
        }
 }
 
+/*
+ * Indexing mechanism for a room list, called by gotoroomstep()
+ */
+void room_tree_list_query(struct ctdlroomlisting *rp, char *findrmname, int findrmslot, char *rmname, int *rmslot, int *rmtotal)
+{
+       char roomname[ROOMNAMELEN];
+       static int cur_rmslot = 0;
+
+       if (rp == NULL) {
+               cur_rmslot = 0;
+               return;
+       }
+
+       if (rp->lnext != NULL) {
+               room_tree_list_query(rp->lnext, findrmname, findrmslot, rmname, rmslot, rmtotal);
+       }
+
+       if (sigcaught == 0) {
+               strcpy(roomname, rp->rlname);
+
+               if (rmname != NULL) {
+                       if (cur_rmslot == findrmslot) {
+                               strcpy(rmname, roomname);
+                       }
+               }
+               if (rmslot != NULL) {
+                       if (!strcmp(roomname, findrmname)) {
+                               *rmslot = cur_rmslot;
+                       }
+               }
+               cur_rmslot++;
+       }
+
+       if (rp->rnext != NULL) {
+               room_tree_list_query(rp->rnext, findrmname, findrmslot, rmname, rmslot, rmtotal);
+       }
+
+       if ((rmname == NULL) && (rmslot == NULL))
+               free(rp);
+
+       if (rmtotal != NULL) {
+               *rmtotal = cur_rmslot;
+       }
+}
+
+/*
+ * step through rooms on current floor
+ */
+void  gotoroomstep(CtdlIPC *ipc, int direction, int mode)
+{
+       struct march *listing = NULL;
+       struct march *mptr;
+       int r;          /* IPC response code */
+       char buf[SIZ];
+       struct ctdlroomlisting *rl = NULL;
+       struct ctdlroomlisting *rp;
+       struct ctdlroomlisting *rs;
+       int list_it;
+       char rmname[ROOMNAMELEN];
+       int rmslot;
+       int rmtotal;
+
+       /* Ask the server for a room list */
+       r = CtdlIPCKnownRooms(ipc, SubscribedRooms, (-1), &listing, buf);
+       if (r / 100 != 1) {
+               listing = NULL;
+       }
+
+       load_floorlist(ipc);
+
+       for (mptr = listing; mptr != NULL; mptr = mptr->next) {
+               list_it = 1;
+
+               if ( floor_mode 
+                        && (mptr->march_floor != curr_floor))
+                       list_it = 0;
+
+               if (list_it) {
+                       rp = malloc(sizeof(struct ctdlroomlisting));
+                       strncpy(rp->rlname, mptr->march_name, ROOMNAMELEN);
+                       rp->rlflags = mptr->march_flags;
+                       rp->rlfloor = mptr->march_floor;
+                       rp->rlorder = mptr->march_order;
+                       rp->lnext = NULL;
+                       rp->rnext = NULL;
+
+                       rs = rl;
+                       if (rl == NULL) {
+                               rl = rp;
+                       } else {
+                               while (rp != NULL) {
+                                       if (rordercmp(rp, rs) < 0) {
+                                               if (rs->lnext == NULL) {
+                                                       rs->lnext = rp;
+                                                       rp = NULL;
+                                               } else {
+                                                       rs = rs->lnext;
+                                               }
+                                       } else {
+                                               if (rs->rnext == NULL) {
+                                                       rs->rnext = rp;
+                                                       rp = NULL;
+                                               } else {
+                                                       rs = rs->rnext;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Find position of current room */
+       room_tree_list_query(NULL, NULL, 0, NULL, NULL, NULL);
+       room_tree_list_query(rl,  room_name, 0, NULL, &rmslot, &rmtotal);
+
+       if (direction == 0) { /* Previous room */
+               /* If we're at the first room, wrap to the last room */
+               if (rmslot == 0) {
+                       rmslot = rmtotal - 1;
+               } else {
+                       rmslot--;
+               }
+       } else {                 /* Next room */
+               /* If we're at the last room, wrap to the first room */
+               if (rmslot == rmtotal - 1) {
+                       rmslot = 0; 
+               } else {
+                       rmslot++;
+               }
+       }
+
+       /* Get name of next/previous room */
+       room_tree_list_query(NULL, NULL, 0, NULL, NULL, NULL);
+       room_tree_list_query(rl,  NULL, rmslot, rmname, NULL, NULL);
+
+       /* Free the tree */
+       room_tree_list_query(rl, NULL, 0, NULL, NULL, NULL);
+
+       if (mode == 0) { /* not skipping */
+           updatels(ipc);
+       } else {
+               if (rc_alt_semantics) {
+               updatelsa(ipc);
+               }
+       }
+       dotgoto(ipc, rmname, 1, 0);
+}
+
+
+/*
+ * step through floors on system
+ */
+void  gotofloorstep(CtdlIPC *ipc, int direction, int mode)
+{
+       int  tofloor;
+
+       if (floorlist[0][0] == 0)
+               load_floorlist(ipc);
+
+       if (direction == 0) { /* Previous floor */
+               if (curr_floor) tofloor = curr_floor - 1;
+               else tofloor = 127;
+
+               while (!floorlist[tofloor][0]) tofloor--;
+       } else {                   /* Next floor */
+               if (curr_floor < 127) tofloor = curr_floor + 1;
+               else tofloor = 0;
+
+               while (!floorlist[tofloor][0] && tofloor < 127) tofloor++;
+               if (!floorlist[tofloor][0])     tofloor = 0;
+       }
+       /* ;g works when not in floor mode so . . . */
+       if (!floor_mode) {
+               scr_printf("(%s)\n", floorlist[tofloor] );
+       }
+
+       gotofloor(ipc, floorlist[tofloor], mode);
+}
+
+/* 
+ * Display user 'preferences'.
+ */
+extern int rc_prompt_control;
+void read_config(CtdlIPC *ipc)
+{
+       char buf[SIZ];
+       char *resp = NULL;
+       int r;                  /* IPC response code */
+    char _fullname[USERNAME_SIZE];
+       long _usernum;
+       int _axlevel, _timescalled, _posted;
+       time_t _lastcall;
+       struct ctdluser *user = NULL;
+
+       /* get misc user info */   
+       r = CtdlIPCGetBio(ipc, fullname, &resp, buf);
+       if (r / 100 != 1) {
+               pprintf("%s\n", buf);
+               return;
+       }
+       extract_token(_fullname, buf, 1, '|', sizeof fullname);
+       _usernum = extract_long(buf, 2);
+       _axlevel = extract_int(buf, 3);
+       _lastcall = extract_long(buf, 4);
+    _timescalled = extract_int(buf, 5);
+       _posted = extract_int(buf, 6);
+       free(resp);
+       resp = NULL;
+   
+       /* get preferences */
+       r = CtdlIPCGetConfig(ipc, &user, buf);
+       if (r / 100 != 2) {
+               scr_printf("%s\n", buf);
+               free(user);
+               return;
+       }
+
+       /* show misc user info */
+       scr_printf("%s\nAccess level: %d (%s)\n"
+                  "User #%ld / %d Calls / %d Posts",
+                  _fullname, _axlevel, axdefs[(int) _axlevel],
+                  _usernum, _timescalled, _posted);
+       if (_lastcall > 0L) {
+               scr_printf(" / Curr login: %s",
+                          asctime(localtime(&_lastcall)));
+       }
+       scr_printf("\n");
+
+       /* show preferences */
+       scr_printf("Your screen width: ");                                     color(BRIGHT_CYAN); scr_printf("%d",   /*user->USscreenwidth*/ screenwidth);          color(DIM_WHITE); 
+       scr_printf(", height: ");                                              color(BRIGHT_CYAN); scr_printf("%d\n", /*user->USscreenheight*/ screenheight);        color(DIM_WHITE);  
+       scr_printf("Are you an experienced Citadel user: ");                   color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_EXPERT) ? "Yes" : "No");     color(DIM_WHITE);
+       scr_printf("Print last old message on New message request: ");         color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_LASTOLD)? "Yes" : "No");     color(DIM_WHITE);
+       scr_printf("Prompt after each message: ");                             color(BRIGHT_CYAN); scr_printf("%s\n", (!(user->flags & US_NOPROMPT))? "Yes" : "No"); color(DIM_WHITE);
+       if ((user->flags & US_NOPROMPT) == 0) {
+       scr_printf("Use 'disappearing' prompts: ");                        color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_DISAPPEAR)? "Yes" : "No");   color(DIM_WHITE);
+       }
+       scr_printf("Pause after each screenful of text: ");                    color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_PAGINATOR)? "Yes" : "No");   color(DIM_WHITE);
+    if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) {
+       scr_printf("<N>ext and <S>top work at paginator prompt: ");        color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_PROMPTCTL)? "Yes" : "No");   color(DIM_WHITE);
+       }
+    if (rc_floor_mode == RC_DEFAULT) {
+       scr_printf("View rooms by floor: ");                               color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_FLOORS)? "Yes" : "No");          color(DIM_WHITE);
+       }
+       if (rc_ansi_color == 3) {
+           scr_printf("Enable color support: ");                              color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_COLOR)? "Yes" : "No");       color(DIM_WHITE);
+       }
+       scr_printf("Be unlisted in userlog: ");                                color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_UNLISTED)? "Yes" : "No");    color(DIM_WHITE);
+       if (strlen(editor_paths[0]) > 0) {
+       scr_printf("Always enter messages with the full-screen editor: "); color(BRIGHT_CYAN); scr_printf("%s\n", (user->flags & US_EXTEDIT)? "Yes" : "No");     color(DIM_WHITE);
+       }
+       free(user);
+}
+
+/*
+ * Display system statistics.
+ */
+void system_info(CtdlIPC *ipc)
+{
+       char buf[SIZ];
+       char *resp = NULL;
+       size_t bytes;
+       int mrtg_users, mrtg_active_users; 
+       char mrtg_server_uptime[40];
+       long mrtg_himessage;
+       int ret;                        /* IPC response code */
+
+       /* get #users, #active & server uptime */
+       ret = CtdlIPCGenericCommand(ipc, "MRTG|users", NULL, 0, &resp, &bytes, buf);
+       mrtg_users = extract_int(resp, 0);
+       remove_token(resp, 0, '\n');
+       mrtg_active_users = extract_int(resp, 0);
+       remove_token(resp, 0, '\n');
+       extract_token(mrtg_server_uptime, resp, 0, '\n', sizeof mrtg_server_uptime);
+    free(resp);
+       resp = NULL;
+
+       /* get high message# */
+       ret = CtdlIPCGenericCommand(ipc, "MRTG|messages", NULL, 0, &resp, &bytes, buf);
+       mrtg_himessage = extract_long(resp, 0);
+       free(resp);
+       resp = NULL;
+
+       /* refresh server info just in case */
+       CtdlIPCServerInfo(ipc, buf);
+
+       scr_printf("You are connected to %s (%s) @%s\n", ipc->ServInfo.nodename, ipc->ServInfo.humannode, ipc->ServInfo.fqdn);
+       scr_printf("running %s with text client v%.2f,\n", ipc->ServInfo.software, (float)REV_LEVEL/100);
+    scr_printf("and located in %s.\n", ipc->ServInfo.site_location);
+    scr_printf("Connected users %d / Active users %d / Highest message #%ld\n", mrtg_users, mrtg_active_users, mrtg_himessage);
+    scr_printf("Server uptime: %s\n", mrtg_server_uptime);
+    scr_printf("Your system administrator is %s.\n", ipc->ServInfo.sysadm);
+    scr_printf("Copyright (C)1987-2006 by the Citadel development team\n");
+}
 
 /*
  * forget all rooms on current floor
@@ -801,8 +1098,15 @@ void get_serv_info(CtdlIPC *ipc, char *supplied_hostname)
                 /* Look up the , in the bible if you're confused */
                 (locate_host(ipc, buf), buf), buf);
 
-       /* Tell the server what our preferred content formats are */
-       if ((CtdlIPCSpecifyPreferredFormats(ipc, buf, "text/html|text/plain") / 100 )== 2) {
+       /*
+        * Tell the server what our preferred content formats are.
+        *
+        * Originally we preferred HTML over plain text because we can format
+        * it to the reader's screen width, but since our HTML-to-text parser
+        * isn't really all that great, it's probably better to just go with
+        * the plain text when we have it available.
+        */
+       if ((CtdlIPCSpecifyPreferredFormats(ipc, buf, "text/plain|text/html") / 100 )== 2) {
                can_do_msg4 = 1;
        }
 }
@@ -1041,6 +1345,15 @@ int main(int argc, char **argv)
        CtdlIPC* ipc;                   /* Our server connection */
        int r;                          /* IPC result code */
 
+       int relh=0;
+       int home=0;
+       char relhome[PATH_MAX]="";
+       char ctdldir[PATH_MAX]=CTDLDIR;
+
+
+
+       calc_dirs_n_files(relh, home, relhome, ctdldir);
+       
        setIPCDeathHook(screen_delete);
        setIPCErrorPrintf(err_printf);
        setCryptoStatusHook(statusHook);
@@ -1122,13 +1435,7 @@ int main(int argc, char **argv)
                         * guaranteed to have the uid/gid we want.
                         */
                        if (!getuid() || !getgid()) {
-                               if (stat(
-#ifndef HAVE_ETC_DIR
-                                                CTDLDIR 
-#else
-                                                ETC_DIR
-#endif
-                                                "/citadel.config", &st) < 0) {
+                               if (stat(file_citadel_config, &st) < 0) {
                                        perror("couldn't stat citadel.config");
                                        logoff(NULL, 3);
                                }
@@ -1148,6 +1455,7 @@ int main(int argc, char **argv)
                        argc = shift(argc, argv, a, 1);
                }
        }
+       
 
        screen_new();
 
@@ -1298,11 +1606,16 @@ int main(int argc, char **argv)
        goto GSTA;
 
 NEWUSR:        if (strlen(rc_password) == 0) {
-               scr_printf("'%s' not found.\n"
-                       "Do you want to create a new account with this name? ",
+               scr_printf("'%s' not found.\n", fullname);
+               scr_printf("Type 'off' if you would like to exit.\n");
+               if (ipc->ServInfo.newuser_disabled == 1) {
+                       goto GSTA;
+               }
+               scr_printf("Do you want to create a new user account called '%s'? ",
                        fullname);
-               if (yesno() == 0)
+               if (yesno() == 0) {
                        goto GSTA;
+               }
        }
 
        r = CtdlIPCCreateUser(ipc, fullname, 1, aaa);
@@ -1364,9 +1677,9 @@ NEWUSR:   if (strlen(rc_password) == 0) {
         * program.  Don't mess with these once they've been set, because we
         * will be unlinking them later on in the program and we don't
         * want to delete something that we didn't create. */
-       snprintf(temp, sizeof temp, tmpnam(NULL));
-       snprintf(temp2, sizeof temp2, tmpnam(NULL));
-       snprintf(tempdir, sizeof tempdir, tmpnam(NULL));
+       CtdlMakeTempFileName(temp, sizeof temp);
+       CtdlMakeTempFileName(temp2, sizeof temp2);
+       CtdlMakeTempFileName(tempdir, sizeof tempdir);
 
        /* Get screen dimensions.  First we go to a default of 80x24.  Then
         * we try to get the user's actual screen dimensions off the server.
@@ -1416,7 +1729,7 @@ NEWUSR:   if (strlen(rc_password) == 0) {
                                formout(ipc, "help");
                                break;
                        case 4:
-                               entmsg(ipc, 0, 0);
+                               entmsg(ipc, 0, ((userflags & US_EXTEDIT) ? 2 : 0));
                                break;
                        case 36:
                                entmsg(ipc, 0, 1);
@@ -1840,6 +2153,46 @@ NEWUSR:  if (strlen(rc_password) == 0) {
                                page_user(ipc);
                                break;
 
+            case 110:           /* <+> Next room */
+                 gotoroomstep(ipc, 1, 0);
+                            break;
+
+            case 111:           /* <-> Previous room */
+                 gotoroomstep(ipc, 0, 0);
+                            break;
+
+                       case 112:           /* <>> Next floor */
+                 gotofloorstep(ipc, 1, GF_GOTO);
+                            break;
+
+                       case 113:           /* <<> Previous floor */
+                 gotofloorstep(ipc, 0, GF_GOTO);
+                                break;
+
+            case 116:           /* <.> skip to <+> Next room */
+                 gotoroomstep(ipc, 1, 1);
+                            break;
+
+            case 117:           /* <.> skip to <-> Previous room */
+                 gotoroomstep(ipc, 0, 1);
+                            break;
+
+                       case 118:           /* <.> skip to <>> Next floor */
+                 gotofloorstep(ipc, 1, GF_SKIP);
+                            break;
+
+                       case 119:           /* <.> skip to <<> Previous floor */
+                 gotofloorstep(ipc, 0, GF_SKIP);
+                                break;
+
+                       case 114:           
+                 read_config(ipc);
+                                break;
+
+                       case 115:           
+                 system_info(ipc);
+                                break;
+
                        default: /* allow some math on the command */
                                /* commands 100... to 100+MAX_EDITORS-1 will
                                   call the appropriate editor... in other