/*
- * Citadel/UX
- *
- * citadel.c - Main source file.
* $Id$
+ *
+ * Main source module for the client program.
*/
#include "sysdep.h"
#include <ctype.h>
#include <string.h>
#include <time.h>
+#include <limits.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "commands.h"
#include "ipc.h"
#include "client_chat.h"
+#include "client_passwords.h"
#include "citadel_decls.h"
#include "tools.h"
+#include "acconfig.h"
#ifndef HAVE_SNPRINTF
#include "snprintf.h"
#endif
+#include "md5.h"
+
struct march {
struct march *next;
- char march_name[32];
+ char march_name[ROOMNAMELEN];
char march_floor;
char march_order;
-};
+ };
#define IFEXPERT if (userflags&US_EXPERT)
#define IFNEXPERT if ((userflags&US_EXPERT)==0)
struct march *march = NULL;
/* globals associated with the client program */
-char temp[16]; /* Name of general temp file */
-char temp2[16]; /* Name of general temp file */
-char tempdir[16]; /* Name of general temp dir */
-char editor_path[256]; /* path to external editor */
-char printcmd[256]; /* print command */
+char temp[PATH_MAX]; /* Name of general temp file */
+char temp2[PATH_MAX]; /* Name of general temp file */
+char tempdir[PATH_MAX]; /* Name of general temp dir */
+char editor_path[SIZ]; /* path to external editor */
+char printcmd[SIZ]; /* print command */
int editor_pid = (-1);
char fullname[32];
jmp_buf nextbuf;
char have_xterm = 0; /* are we running on an xterm? */
char rc_username[32];
char rc_password[32];
+char hostbuf[SIZ];
+char portbuf[SIZ];
char rc_floor_mode;
char floor_mode;
char curr_floor = 0; /* number of current floor */
-char floorlist[128][256]; /* names of floors */
+char floorlist[128][SIZ]; /* names of floors */
char express_msgs = 0; /* express messages waiting! */
+int termn8 = 0; /* Set to nonzero to cause a logoff */
-jmp_buf jmp_reconnect; /* for server reconnects */
-char re_username[32];
-char re_password[32];
-
-void sigpipehandler(int nothing)
-{
- longjmp(jmp_reconnect, nothing);
-}
+extern int rc_ansi_color; /* ansi color value from citadel.rc */
/*
* here is our 'clean up gracefully and exit' routine
-/*
- * We handle "next" and "stop" much differently than in earlier versions.
- * The signal catching routine simply sets a flag and returns.
- */
-void sighandler(int which_sig)
-{
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- sigcaught = which_sig;
- return;
-}
-
-
/*
* signal catching function for hangups...
*/
void formout(char *name)
{ /* display a file */
- char cmd[256];
+ char cmd[SIZ];
snprintf(cmd, sizeof cmd, "MESG %s", name);
serv_puts(cmd);
serv_gets(cmd);
}
-void userlist(void)
+void userlist(char *patn)
{
- char buf[256];
- char fl[256];
+ char buf[SIZ];
+ char fl[SIZ];
struct tm *tmbuf;
time_t lc;
- int linecount = 2;
serv_puts("LIST");
serv_gets(buf);
if (buf[0] != '1') {
- printf("%s\n", &buf[4]);
+ pprintf("%s\n", &buf[4]);
return;
}
- sigcaught = 0;
- sttybbs(SB_YES_INTR);
- printf(" User Name Num L LastCall Calls Posts\n");
- printf("------------------------- ----- - ---------- ----- -----\n");
+ pprintf(" User Name Num L LastCall Calls Posts\n");
+ pprintf("------------------------- ----- - ---------- ----- -----\n");
while (serv_gets(buf), strcmp(buf, "000")) {
if (sigcaught == 0) {
- extract(fl, buf, 0);
- printf("%-25s ", fl);
- printf("%5ld %d ", extract_long(buf, 2),
+ extract(fl, buf, 0);
+ if (pattern(fl, patn) >= 0) {
+ pprintf("%-25s ", fl);
+ pprintf("%5ld %d ", extract_long(buf, 2),
extract_int(buf, 1));
lc = extract_long(buf, 3);
tmbuf = (struct tm *) localtime(&lc);
- printf("%02d/%02d/%04d ",
+ pprintf("%02d/%02d/%04d ",
(tmbuf->tm_mon + 1),
tmbuf->tm_mday,
(tmbuf->tm_year + 1900));
- printf("%5ld %5ld\n", extract_long(buf, 4), extract_long(buf, 5));
-
- ++linecount;
- linecount = checkpagin(linecount,
- ((userflags & US_PAGINATOR) ? 1 : 0),
- screenheight);
+ pprintf("%5ld %5ld\n", extract_long(buf, 4), extract_long(buf, 5));
+ }
}
}
- sttybbs(SB_NO_INTR);
- printf("\n");
+ pprintf("\n");
}
if (march == NULL)
return;
- if ((!strucmp(march->march_name, roomname))
- || ((!strucmp(roomname, "_FLOOR_")) && (march->march_floor == floornum))) {
+ if ((!strcasecmp(march->march_name, roomname))
+ || ((!strcasecmp(roomname, "_FLOOR_")) && (march->march_floor == floornum))) {
mptr = march->next;
free(march);
march = mptr;
mptr2 = march;
for (mptr = march; mptr != NULL; mptr = mptr->next) {
- if ((!strucmp(mptr->march_name, roomname))
- || ((!strucmp(roomname, "_FLOOR_"))
+ if ((!strcasecmp(mptr->march_name, roomname))
+ || ((!strcasecmp(roomname, "_FLOOR_"))
&& (mptr->march_floor == floornum))) {
mptr2->next = mptr->next;
*/
void dotgoto(char *towhere, int display_name)
{
- char aaa[256], bbb[256], psearch[256];
+ char aaa[SIZ], bbb[SIZ], psearch[SIZ];
static long ls = 0L;
int newmailcount;
static int oldmailcount = (-1);
if (pattern(psearch, towhere) >= 0) {
partial_match = 1;
}
- if (!struncmp(towhere, psearch, strlen(towhere))) {
+ if (!strncasecmp(towhere, psearch, strlen(towhere))) {
partial_match = 2;
}
if (partial_match > best_match) {
curr_floor = extract_int(&aaa[4], 10);
remove_march(room_name, 0);
- if (!strucmp(towhere, "_BASEROOM_"))
+ if (!strcasecmp(towhere, "_BASEROOM_"))
remove_march(towhere, 0);
if ((from_floor != curr_floor) && (display_name > 0) && (floor_mode == 1)) {
if (floorlist[(int) curr_floor][0] == 0)
*/
void gotonext(void)
{
- char buf[256];
+ char buf[SIZ];
struct march *mptr, *mptr2;
- char next_room[32];
+ char next_room[ROOMNAMELEN];
/* Check to see if the march-mode list is already allocated.
* If it is, pop the first room off the list and go there.
*/
void forget_all_rooms_on(int ffloor)
{
- char buf[256];
+ char buf[SIZ];
struct march *flist, *fptr;
printf("Forgetting all rooms on %s...\r", &floorlist[ffloor][0]);
{
int a, tofloor;
struct march *mptr;
- char buf[256], targ[256];
+ char buf[SIZ], targ[SIZ];
if (floorlist[0][0] == 0)
load_floorlist();
tofloor = (-1);
for (a = 0; a < 128; ++a)
- if (!strucmp(&floorlist[a][0], towhere))
+ if (!strcasecmp(&floorlist[a][0], towhere))
tofloor = a;
if (tofloor < 0) {
for (a = 0; a < 128; ++a) {
- if (!struncmp(&floorlist[a][0], towhere, strlen(towhere))) {
+ if (!strncasecmp(&floorlist[a][0], towhere, strlen(towhere))) {
tofloor = a;
}
}
{
char pass1[20];
char pass2[20];
- char buf[256];
+ char buf[SIZ];
if (strlen(rc_password) > 0) {
strcpy(pass1, rc_password);
newprompt("Enter a new password: ", pass1, -19);
newprompt("Enter it again to confirm: ", pass2, -19);
}
- if (!strucmp(pass1, pass2)) {
+ strproc(pass1);
+ strproc(pass2);
+ if (!strcasecmp(pass1, pass2)) {
snprintf(buf, sizeof buf, "SETP %s", pass1);
serv_puts(buf);
serv_gets(buf);
printf("%s\n", &buf[4]);
- strcpy(re_password, pass1);
+ offer_to_remember_password(hostbuf, portbuf, fullname, pass1);
return (0);
} else {
printf("*** They don't match... try again.\n");
/*
* get info about the server we've connected to
*/
-void get_serv_info(void)
+void get_serv_info(char *supplied_hostname)
{
char buf[512];
snprintf(buf, sizeof buf, "IDEN %d|%d|%d|%s|",
SERVER_TYPE, 0, REV_LEVEL,
(server_is_local ? "local" : CITADEL));
- locate_host(&buf[strlen(buf)]); /* append to the end */
+
+ /* Append a hostname */
+ if (supplied_hostname != NULL) {
+ strcat(buf, supplied_hostname);
+ }
+ else {
+ locate_host(&buf[strlen(buf)]); /* append to the end */
+ }
+
serv_puts(buf);
serv_gets(buf); /* we don't care about the result code */
}
*/
void who_is_online(int longlist)
{
- char buf[128], username[128], roomname[128], fromhost[128],
- flags[128];
- char tbuf[128], clientsoft[128];
+ char buf[SIZ], username[SIZ], roomname[SIZ], fromhost[SIZ];
+ char flags[SIZ];
+ char actual_user[SIZ], actual_room[SIZ], actual_host[SIZ];
+ char tbuf[SIZ], clientsoft[SIZ];
time_t timenow = 0;
time_t idletime, idlehours, idlemins, idlesecs;
int last_session = (-1);
- if (longlist) {
- serv_puts("TIME");
- serv_gets(tbuf);
- if (tbuf[0] == '2') {
- timenow = extract_long(&tbuf[4], 0);
- } else {
- time(&timenow);
- }
- } else {
+ serv_puts("TIME");
+ serv_gets(tbuf);
+ if (tbuf[0] == '2') {
+ timenow = extract_long(&tbuf[4], 0);
+ }
+ else {
+ time(&timenow);
+ }
+
+ if (!longlist) {
color(BRIGHT_WHITE);
- printf("FLG ### User Name Room From host\n");
+ pprintf("FLG ### User Name Room From host\n");
color(DIM_WHITE);
- printf("--- --- ------------------------- -------------------- ------------------------\n");
+ pprintf("--- --- ------------------------- -------------------- ------------------------\n");
}
serv_puts("RWHO");
serv_gets(buf);
extract(clientsoft, buf, 4);
extract(flags, buf, 7);
+ idletime = timenow - extract_long(buf, 5);
+ idlehours = idletime / 3600;
+ idlemins = (idletime - (idlehours * 3600)) / 60;
+ idlesecs = (idletime - (idlehours * 3600) - (idlemins * 60));
+
+ if (idletime > 900) {
+ while (strlen(roomname) < 20) {
+ strcat(roomname, " ");
+ }
+ strcpy(&roomname[14], "[idle]");
+ }
+
if (longlist) {
- idletime = timenow - extract_long(buf, 5);
- idlehours = idletime / 3600;
- idlemins = (idletime - (idlehours * 3600)) / 60;
- idlesecs = (idletime - (idlehours * 3600) - (idlemins * 60));
- printf("\nFlags: %-3s Sess# %-3d Name: %-25s Room: %s\n",
+
+ extract(actual_user, buf, 8);
+ extract(actual_room, buf, 9);
+ extract(actual_host, buf, 10);
+
+ pprintf("\nFlags: %-3s Sess# %-3d Name: %-25s Room: %s\n",
flags, extract_int(buf, 0), username, roomname);
- printf("from <%s> using <%s>, idle %ld:%02ld:%02ld\n",
+ pprintf("from <%s> using <%s>, idle %ld:%02ld:%02ld\n",
fromhost, clientsoft,
(long) idlehours, (long) idlemins, (long) idlesecs);
+ if ( (strlen(actual_user)+strlen(actual_room)+strlen(actual_host)) > 0) {
+ pprintf("(really ");
+ if (strlen(actual_user)>0) pprintf("<%s> ", actual_user);
+ if (strlen(actual_room)>0) pprintf("in <%s> ", actual_room);
+ if (strlen(actual_host)>0) pprintf("from <%s> ", actual_host);
+ pprintf(")\n");
+ }
+
} else {
if (extract_int(buf, 0) == last_session) {
- printf(" ");
+ pprintf(" ");
} else {
color(BRIGHT_MAGENTA);
- printf("%-3s ", flags);
+ pprintf("%-3s ", flags);
color(DIM_WHITE);
- printf("%-3d ", extract_int(buf, 0));
+ pprintf("%-3d ", extract_int(buf, 0));
}
last_session = extract_int(buf, 0);
color(BRIGHT_CYAN);
- printf("%-25s ", username);
+ pprintf("%-25s ", username);
color(BRIGHT_MAGENTA);
- printf("%-20s ", roomname);
+ roomname[20] = 0;
+ pprintf("%-20s ", roomname);
color(BRIGHT_CYAN);
- printf("%-24s\n", fromhost);
+ pprintf("%-24s\n", fromhost);
color(DIM_WHITE);
}
}
newprompt(bbb, buf, maxlen);
}
+
+
+int shift(int argc, char **argv, int start, int count) {
+ int i;
+
+ for (i=start; i<(argc-count); ++i) {
+ argv[i] = argv[i+count];
+ }
+ argc = argc - count;
+ return argc;
+}
+
/*
* main
*/
int main(int argc, char **argv)
{
int a, b, mcmd;
- char aaa[100], bbb[100], eee[100]; /* general purpose variables */
+ char aaa[100], bbb[100];/* general purpose variables */
char argbuf[32]; /* command line buf */
- volatile int termn8 = 0;
-
+ char nonce[NONCE_SIZE];
+ char *telnet_client_host = NULL;
+ char *sptr, *sptr2; /* USed to extract the nonce */
+ char hexstring[MD5_HEXSTRING_SIZE];
+ int stored_password = 0;
+ char password[SIZ];
sttybbs(SB_SAVE); /* Store the old terminal parameters */
load_command_set(); /* parse the citadel.rc file */
sttybbs(SB_NO_INTR); /* Install the new ones */
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, dropcarr); /* Cleanup gracefully if carrier is dropped */
signal(SIGTERM, dropcarr); /* Cleanup gracefully if terminated */
signal(SIGCONT, catch_sigcont); /* Catch SIGCONT so we can reset terminal */
- printf("Attaching to server...\r");
+ /*
+ * Handle command line options as if we were called like /bin/login
+ * (i.e. from in.telnetd)
+ */
+ for (a=0; a<argc; ++a) {
+ if ((argc > a+1) && (!strcmp(argv[a], "-h")) ) {
+ telnet_client_host = argv[a+1];
+ argc = shift(argc, argv, a, 2);
+ }
+ if (!strcmp(argv[a], "-p")) {
+ argc = shift(argc, argv, a, 1);
+ }
+ }
+
+ printf("Attaching to server... \r");
fflush(stdout);
- attach_to_server(argc, argv);
+ attach_to_server(argc, argv, hostbuf, portbuf);
send_ansi_detect();
printf("%s\n", &aaa[4]);
logoff(atoi(aaa));
}
- get_serv_info();
+
+/* If there is a [nonce] at the end, put the nonce in <nonce>, else nonce
+ * is zeroized.
+ */
+
+ if ((sptr = strchr(aaa, '<')) == NULL)
+ {
+ nonce[0] = '\0';
+ }
+ else
+ {
+ if ((sptr2 = strchr(sptr, '>')) == NULL)
+ {
+ nonce[0] = '\0';
+ }
+ else
+ {
+ sptr2++;
+ *sptr2 = '\0';
+ strncpy(nonce, sptr, NONCE_SIZE);
+ }
+ }
+
+ get_serv_info(telnet_client_host);
look_for_ansi();
cls(0);
color(7);
- printf("%-22s\n%s\n%s\n", serv_info.serv_software, serv_info.serv_humannode,
+ printf("%-23s\n%s\n%s\n", serv_info.serv_software, serv_info.serv_humannode,
serv_info.serv_bbs_city);
screenwidth = 80; /* default screen dimensions */
screenheight = 24;
formout("hello"); /* print the opening greeting */
printf("\n");
- GSTA:termn8 = 0;
+GSTA: /* See if we have a username and password on disk */
+ if (rc_remember_passwords) {
+ get_stored_password(hostbuf, portbuf, fullname, password);
+ if (strlen(fullname) > 0) {
+ snprintf(aaa, sizeof(aaa)-1, "USER %s", fullname);
+ serv_puts(aaa);
+ serv_gets(aaa);
+ if (nonce[0])
+ {
+ sprintf(aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring));
+ }
+ else /* Else no APOP */
+ {
+ snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
+ }
+
+ serv_puts(aaa);
+ serv_gets(aaa);
+ if (aaa[0] == '2') {
+ load_user_info(&aaa[4]);
+ stored_password = 1;
+ goto PWOK;
+ }
+ else {
+ set_stored_password(hostbuf, portbuf, "", "");
+ }
+ }
+ }
+
+ termn8 = 0;
newnow = 0;
do {
if (strlen(rc_username) > 0) {
newprompt("Enter your name: ", fullname, 29);
}
strproc(fullname);
- if (!strucmp(fullname, "new")) { /* just in case */
+ if (!strcasecmp(fullname, "new")) { /* just in case */
printf("Please enter the name you wish to log in with.\n");
}
} while (
- (!strucmp(fullname, "bbs"))
- || (!strucmp(fullname, "new"))
+ (!strcasecmp(fullname, "bbs"))
+ || (!strcasecmp(fullname, "new"))
|| (strlen(fullname) == 0));
- if (!strucmp(fullname, "off")) {
+ if (!strcasecmp(fullname, "off")) {
mcmd = 29;
goto TERMN8;
}
/* sign on to the server */
- strcpy(re_username, fullname);
snprintf(aaa, sizeof aaa, "USER %s", fullname);
serv_puts(aaa);
serv_gets(aaa);
/* password authentication */
if (strlen(rc_password) > 0) {
- strcpy(eee, rc_password);
+ strcpy(password, rc_password);
} else {
- newprompt("\rPlease enter your password: ", eee, -19);
+ newprompt("\rPlease enter your password: ", password, -19);
+ }
+ strproc(password);
+
+ if (nonce[0])
+ {
+ sprintf(aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring));
+ }
+ else /* Else no APOP */
+ {
+ snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
}
- strproc(eee);
- snprintf(aaa, sizeof aaa, "PASS %s", eee);
+
serv_puts(aaa);
serv_gets(aaa);
if (aaa[0] == '2') {
- strcpy(re_password, eee);
load_user_info(&aaa[4]);
+ offer_to_remember_password(hostbuf, portbuf,
+ fullname, password);
goto PWOK;
}
printf("<< wrong password >>\n");
logoff(0);
goto GSTA;
- NEWUSR:if (strlen(rc_password) == 0) {
+NEWUSR: if (strlen(rc_password) == 0) {
printf("No record. Enter as new user? ");
if (yesno() == 0)
goto GSTA;
enter_config(1);
+PWOK:
+ /* Switch color support on or off if we're in user mode */
+ if (rc_ansi_color == 3) {
+ if (userflags & US_COLOR)
+ enable_color = 1;
+ else
+ enable_color = 0;
+ }
- PWOK:printf("%s\nAccess level: %d (%s)\nUser #%ld / Call #%d\n",
+ printf("%s\nAccess level: %d (%s)\nUser #%ld / Call #%d\n",
fullname, axlevel, axdefs[(int) axlevel],
usernum, timescalled);
* 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, "/tmp/citA%d", getpid());
- snprintf(temp2, sizeof temp2, "/tmp/citB%d", getpid());
- snprintf(tempdir, sizeof tempdir, "/tmp/citC%d", getpid());
+ snprintf(temp, sizeof temp, tmpnam(NULL));
+ snprintf(temp2, sizeof temp2, tmpnam(NULL));
+ snprintf(tempdir, sizeof tempdir, tmpnam(NULL));
/* 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.
else
readmsgs(1, 1, 0);
- do { /* MAIN LOOP OF PROGRAM */
-
- /* Reconnect to the server if the connection was broken */
- if (setjmp(jmp_reconnect)) {
- printf("\rServer connection broken; reconnecting...\r");
- fflush(stdout);
- attach_to_server(argc, argv);
- printf(" \r");
- fflush(stdout);
- serv_gets(aaa);
- if (aaa[0] != '2') {
- printf("%s\n", &aaa[4]);
- exit(0);
- }
- get_serv_info();
- sprintf(aaa, "USER %s", re_username);
- serv_puts(aaa);
- serv_gets(aaa);
- if (aaa[0] != '3') {
- printf("%s\n", &aaa[4]);
- exit(0);
- }
- sprintf(aaa, "PASS %s", re_password);
- serv_puts(aaa);
- serv_gets(aaa);
- if (aaa[0] != '2') {
- printf("%s\n", &aaa[4]);
- exit(0);
- }
- load_user_info(&aaa[4]);
- sprintf(aaa, "GOTO %s", room_name);
- serv_puts(aaa);
- serv_gets(aaa);
- }
- signal(SIGPIPE, sigpipehandler);
-
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- mcmd = getcmd(argbuf);
+ /* MAIN COMMAND LOOP */
+ do {
+ mcmd = getcmd(argbuf); /* Get keyboard command */
#ifdef TIOCGWINSZ
- check_screen_dims();
+ check_screen_dims(); /* if xterm, get screen size */
#endif
if (termn8 == 0)
killroom();
break;
case 32:
- userlist();
+ userlist(argbuf);
break;
case 27:
invite();
}
break;
+ case 85:
+ printf("All users will be disconnected! "
+ "Really terminate the server? ");
+ if (yesno() == 1) {
+ serv_puts("DOWN");
+ serv_gets(aaa);
+ printf("%s\n", &aaa[4]);
+ if (aaa[0]=='2') {
+ updatels();
+ a = 0;
+ termn8 = 1;
+ }
+ }
+
+ case 86:
+ printf("Do you really want to schedule a "
+ "server shutdown? ");
+ if (yesno() == 1) {
+ serv_puts("SCDN 1");
+ serv_gets(aaa);
+ if (aaa[0]=='2') {
+ if (atoi(&aaa[4])) {
+ printf(
+"The Citadel server will terminate when all users are logged off.\n"
+ );
+ }
+ else {
+ printf(
+"The Citadel server will not terminate.\n"
+ );
+ }
+ }
+ }
+
case 6:
gotonext();
break;
do_system_configuration();
break;
+ case 82:
+ do_internet_configuration();
+ break;
+
+ case 83:
+ check_message_base();
+ break;
+
+ case 84:
+ quiet_mode();
+ break;
+
case 50:
enter_config(2);
break;
} /* end switch */
} while (termn8 == 0);
- TERMN8:printf("%s logged out.\n", fullname);
- while (march != NULL)
+TERMN8: printf("%s logged out.\n", fullname);
+ while (march != NULL) {
remove_march(march->march_name, 0);
- if (mcmd == 30)
+ }
+ if (mcmd == 30) {
printf("\n\nType 'off' to hang up, or next user...\n");
+ }
snprintf(aaa, sizeof aaa, "LOUT");
serv_puts(aaa);
serv_gets(aaa);
}
goto GSTA;
-} /* end main() */
+} /* end main() */