$Log$
+Revision 1.472 2000/02/27 03:57:35 ajc
+* Completed 'fsck'-like reference count verifier (server and client)
+
Revision 1.471 2000/02/26 18:30:40 ajc
* Properly handle all aliases specified in network/mail.aliases for incoming
SMTP mail (uses the alias() function, so if we replace that function with
Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
* Initial CVS import
-
do_internet_configuration();
break;
+ case 83:
+ check_message_base();
+ break;
+
case 50:
enter_config(2);
break;
cmd=78,1,&.,&Aide,&Post
cmd=80,2,&.,&Aide,&System configuration,&General
cmd=82,2,&.,&Aide,&System configuration,&Internet
+cmd=83,2,&.,&Aide,&System configuration,check &Message base
cmd=29,0,&.,&Terminate,and &Quit
cmd=30,0,&.,&Terminate,and &Stay online
/*
- * Citadel/UX
- *
- * commands.c - front end for Citadel
- *
- * This version is the traditional command parser for room prompts.
- *
* $Id$
*
+ * This file contains functions which implement parts of the
+ * text-mode user interface.
+ *
*/
#include "sysdep.h"
putc(7, stdout);
}
color(BRIGHT_RED);
- printf("---\n");
+ printf("\r---\n");
while (serv_gets(buf), strcmp(buf, "000")) {
printf("%s\n", buf);
}
return;
time(&idlet);
- /* Do a space-backspace to keep socksified telnet sessions open */
+ /* Do a space-backspace to keep telnet sessions from idling out */
printf(" %c", 8);
fflush(stdout);
}
color(DIM_WHITE);
}
+
+
+
+/*
+ * Present a key-menu line choice type of thing
+ */
+char keymenu(char *menuprompt, char *menustring) {
+ int i, c, a;
+ int choices;
+ int do_prompt = 0;
+ char buf[256];
+ int ch;
+ int display_prompt = 1;
+
+ choices = num_tokens(menustring, '|');
+
+ if (menuprompt != NULL) do_prompt = 1;
+ if (menuprompt != NULL) if (strlen(menuprompt)==0) do_prompt = 0;
+
+ while (1) {
+ if (display_prompt) {
+ if (do_prompt) {
+ printf("%s ", menuprompt);
+ }
+ else {
+ for (i=0; i<choices; ++i) {
+ extract(buf, menustring, i);
+ keyopt(buf);
+ printf(" ");
+ }
+ }
+ printf(" -> ");
+ display_prompt = 0;
+ }
+ ch = lkey();
+
+ if ( (do_prompt) && (ch=='?') ) {
+ printf("\rOne of... ");
+ printf(" \n");
+ for (i=0; i<choices; ++i) {
+ extract(buf, menustring, i);
+ printf(" ");
+ keyopt(buf);
+ printf("\n");
+ }
+ printf("\n");
+ display_prompt = 1;
+ }
+
+ for (i=0; i<choices; ++i) {
+ extract(buf, menustring, i);
+ for (c=1; c<strlen(buf); ++c) {
+ if ( (ch == tolower(buf[c]))
+ && (buf[c-1]=='<')
+ && (buf[c+1]=='>') ) {
+ for (a=0; a<strlen(buf); ++a) {
+ if ( (a!=(c-1)) && (a!=(c+1))) {
+ putc(buf[a], stdout);
+ }
+ }
+ printf("\n\n");
+ return ch;
+ }
+ }
+ }
+ }
+}
int yesno(void);
int yesno_d(int d);
void keyopt(char *);
+char keymenu(char *menuprompt, char *menustring);
extern int num_urls;
extern char urls[MAXURLS][256];
if (e_ex_code==0) goto MEFIN;
goto MEABT2;
}
-MECR1: printf("Entry cmd (? for options) -> ");
-MECR2: b=inkey();
- if (b==NEXT_KEY) b='n';
- if (b==STOP_KEY) b='s';
- b=(b&127); b=tolower(b);
- if (b=='?') {
- printf("Help\n");
- formout("saveopt");
- goto MECR1;
- }
- if (b=='a') { printf("Abort\n"); goto MEABT; }
- if (b=='c') { printf("Continue\n"); goto ME1; }
- if (b=='s') { printf("Save message\n"); goto MEFIN; }
+
+ b = keymenu("Entry command (? for options)",
+ "<A>bort|<C>ontinue|<S>ave message|<P>rint formatted|"
+ "<R>eplace string|<H>old message");
+
+ if (b=='a') goto MEABT;
+ if (b=='c') goto ME1;
+ if (b=='s') goto MEFIN;
if (b=='p') {
- printf("Print formatted\n");
printf(" %s from %s",datestr,fullname);
if (strlen(recipient)>0) printf(" to %s",recipient);
printf("\n");
goto MECR;
}
if (b=='r') {
- printf("Replace string\n");
replace_string(filename,0L);
goto MECR;
}
if (b=='h') {
- printf("Hold message\n");
return(2);
}
- goto MECR2;
MEFIN: return(0);
sprintf(write_cmd, "EMSG %s", which_message);
do_edit(desc, read_cmd, "NOOP", write_cmd);
}
+
+
+
+
+/*
+ * Verify the message base
+ */
+void check_message_base(void) {
+ char buf[256];
+
+ printf("Please read the documentation before running this command.\n");
+ printf("Having done so, do you still want to check the message base? ");
+ if (yesno()==0) return;
+
+ serv_puts("FSCK");
+ serv_gets(buf);
+ if (buf[0] != '1') {
+ printf("%s\n", &buf[4]);
+ return;
+ }
+
+ while (serv_gets(buf), strcmp(buf, "000")) {
+ printf("%s\n", buf);
+ }
+}
extern int lines_printed;
pid_t ka_wait(int *kstatus);
void list_urls(void);
+void check_message_base(void);
+++ /dev/null
-One of:
- <A>bort
- <C>ontinue
- <H>old this message
- <P>rint formatted
- <R>eplace string (edit)
- <S>ave message
color(DIM_WHITE);
}
- keyopt("\n<A>dd <D>elete <S>ave <Q>uit -> ");
- do {
- badkey = 0;
- ch = inkey();
- ch = tolower(ch);
- if ( (ch=='d') && (num_recs == 0) ) ch = 0;
- switch(ch) {
- case 'a':
- printf("Add\n");
- ++num_recs;
- if (num_recs == 1)
- recs = malloc(sizeof(char *));
- else recs = realloc(recs,
- (sizeof(char *)) * num_recs);
- newprompt("Enter host name: ",
- buf, 50);
- strcat(buf, "|");
- get_inet_rec_type(&buf[strlen(buf)]);
- recs[num_recs-1] = strdup(buf);
- break;
- case 'd':
- printf("Delete\n");
- i = intprompt("Delete which one",
- 1, 1, num_recs) - 1;
- free(recs[i]);
- --num_recs;
- for (j=i; j<num_recs; ++j)
- recs[j] = recs[j+1];
- break;
- case 's':
- printf("Save\n");
- sprintf(buf, "CONF putsys|%s",
- INTERNETCFG);
- serv_puts(buf);
- serv_gets(buf);
- if (buf[0] == '4') {
- for (i=0; i<num_recs; ++i) {
- serv_puts(recs[i]);
- }
- serv_puts("000");
- }
- else {
- printf("%s\n", &buf[4]);
+ ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
+ switch(ch) {
+ case 'a':
+ ++num_recs;
+ if (num_recs == 1)
+ recs = malloc(sizeof(char *));
+ else recs = realloc(recs,
+ (sizeof(char *)) * num_recs);
+ newprompt("Enter host name: ",
+ buf, 50);
+ strcat(buf, "|");
+ get_inet_rec_type(&buf[strlen(buf)]);
+ recs[num_recs-1] = strdup(buf);
+ break;
+ case 'd':
+ i = intprompt("Delete which one",
+ 1, 1, num_recs) - 1;
+ free(recs[i]);
+ --num_recs;
+ for (j=i; j<num_recs; ++j)
+ recs[j] = recs[j+1];
+ break;
+ case 's':
+ sprintf(buf, "CONF putsys|%s",
+ INTERNETCFG);
+ serv_puts(buf);
+ serv_gets(buf);
+ if (buf[0] == '4') {
+ for (i=0; i<num_recs; ++i) {
+ serv_puts(recs[i]);
}
- quitting = 1;
- break;
- case 'q':
- printf("Quit\n");
- quitting = boolprompt(
- "Quit without saving", 0);
- break;
- default:
- badkey = 1;
- }
- } while (badkey == 1);
+ serv_puts("000");
+ }
+ else {
+ printf("%s\n", &buf[4]);
+ }
+ quitting = 1;
+ break;
+ case 'q':
+ quitting = boolprompt(
+ "Quit without saving", 0);
+ break;
+ default:
+ badkey = 1;
+ }
} while (quitting == 0);
if (recs != NULL) {
long vu_usernum;
};
+
+struct roomref {
+ struct roomref *next;
+ long msgnum;
+};
+
+
struct PurgeList *UserPurgeList = NULL;
struct PurgeList *RoomPurgeList = NULL;
struct ValidRoom *ValidRoomList = NULL;
struct ValidUser *ValidUserList = NULL;
int messages_purged;
+struct roomref *rr = NULL;
+
extern struct CitContext *ContextList;
void DoPurgeMessages(struct quickroom *qrbuf, void *data) {
/*****************************************************************************/
+void do_fsck_msg(long msgnum) {
+ struct roomref *ptr;
+
+ ptr = (struct roomref *)mallok(sizeof(struct roomref));
+ ptr->next = rr;
+ ptr->msgnum = msgnum;
+ rr = ptr;
+}
+
+void do_fsck_room(struct quickroom *qrbuf, void *data)
+{
+ getroom(&CC->quickroom, qrbuf->QRname);
+ CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, do_fsck_msg);
+}
+
/*
- * Check message reference counts (FIXME ... not yet finished)
+ * Check message reference counts
+ */
void cmd_fsck(char *argbuf) {
long msgnum;
struct cdbdata *cdbmsg;
struct SuppMsgInfo smi;
+ struct roomref *ptr;
+ int realcount;
- cprintf("%d This is not done yet.\n", LISTING_FOLLOWS);
+ if ( (!CC->logged_in) || (CC->usersupp.axlevel < 6) ) {
+ cprintf("%d Higher access required\n",
+ ERROR+HIGHER_ACCESS_REQUIRED);
+ return;
+ }
+
+ /* Lame way of checking whether anyone else is doing this now */
+ if (rr != NULL) {
+ cprintf("%d Another FSCK is already running.\n", ERROR);
+ return;
+ }
+
+ cprintf("%d Checking message reference counts\n", LISTING_FOLLOWS);
+
+ cprintf("\nThis could take a while. Please be patient!\n\n");
+ cprintf("Gathering pointers...\n");
+ ForEachRoom(do_fsck_room, NULL);
get_control();
+ cprintf("Checking message base...\n");
for (msgnum = 0L; msgnum <= CitControl.MMhighest; ++msgnum) {
cdbmsg = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long));
cprintf("Message %7ld ", msgnum);
GetSuppMsgInfo(&smi, msgnum);
- cprintf("refcount=%-2d \n", smi.smi_refcount);
+ cprintf("refcount=%-2d ", smi.smi_refcount);
+
+ realcount = 0;
+ for (ptr = rr; ptr != NULL; ptr = ptr->next) {
+ if (ptr->msgnum == msgnum) ++realcount;
+ }
+ cprintf("realcount=%-2d\n", realcount);
+
+ if ( (smi.smi_refcount != realcount)
+ || (realcount == 0) ) {
+ smi.smi_refcount = realcount;
+ PutSuppMsgInfo(&smi);
+ AdjRefCount(msgnum, 0); /* deletes if needed */
+ }
+
}
}
+ cprintf("Freeing memory...\n");
+ while (rr != NULL) {
+ ptr = rr->next;
+ phree(rr);
+ rr = ptr;
+ }
+
+ cprintf("Done!\n");
cprintf("000\n");
}
- */
char *Dynamic_Module_Init(void)
{
CtdlRegisterProtoHook(cmd_expi, "EXPI", "Expire old system objects");
-/* CtdlRegisterProtoHook(cmd_fsck, "FSCK", "Check message ref counts"); */
+ CtdlRegisterProtoHook(cmd_fsck, "FSCK", "Check message ref counts");
return "$Id$";
}
* The system-dependent part of master_cleanup() - close the master socket.
*/
void sysdep_master_cleanup(void) {
- /* FIXME close all protocol master sockets here */
+ struct ServiceFunctionHook *serviceptr;
+
+ /*
+ * close all protocol master sockets
+ */
+ for (serviceptr = ServiceHookTable; serviceptr != NULL;
+ serviceptr = serviceptr->next ) {
+ lprintf(3, "Closing listener on port %d\n",
+ serviceptr->tcp_port);
+ close(serviceptr->msock);
+ }
}
-> _userpic_ (Server will attempt to write to the user's online photo)
-> Any of the "well known" filenames described in the writeup for the
OIMG command.
-
-----------------------------------------------
-The following are for citserver 5.02 and above
-----------------------------------------------
-
+
+
HCHG (Hostname CHanGe)
HCHG is a command, usable by any user, that allows a user to change their RWHO
CICQ status
Always returns OK followed by a 1 (connected to ICQ) or 0 (not connected).
+
+
+
+
+ FSCK (check message base reference counts)
+
+ Verify, via the long way, that all message referenmce counts are correct. If
+the user has permission to do this then LISTING_FOLLOWS is returned, followed
+by a transcript of the run. Otherwise ERROR is returned.
+