From e61cfdd4e3b31f3a4c73390d58007e67995e6667 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Tue, 23 Apr 2002 03:18:04 +0000 Subject: [PATCH] * Set up the framework for different "views" of a room --- citadel/axdefs.h | 20 +++ citadel/citadel.h | 9 ++ citadel/citserver.c | 239 ++++++++++++++++++------------------ citadel/room_ops.c | 17 ++- citadel/serv_vandelay.c | 4 + citadel/server.h | 1 + citadel/techdoc/session.txt | 11 +- citadel/techdoc/views.txt | 27 ++++ citadel/user_ops.c | 27 ++++ citadel/user_ops.h | 1 + 10 files changed, 233 insertions(+), 123 deletions(-) create mode 100644 citadel/techdoc/views.txt diff --git a/citadel/axdefs.h b/citadel/axdefs.h index 0b3084e66..ecbb5f78d 100644 --- a/citadel/axdefs.h +++ b/citadel/axdefs.h @@ -19,3 +19,23 @@ char *axdefs[]={ extern char *axdefs[]; #endif + + + + +#ifndef VIEWDEFS + +char *viewdefs[]={ + "Messages", + "Summary", + "Address book" +}; + +#define VIEWDEFS 1 + +#else + +extern char *viewdefs[]; + +#endif + diff --git a/citadel/citadel.h b/citadel/citadel.h index 3440e02fd..77102c367 100644 --- a/citadel/citadel.h +++ b/citadel/citadel.h @@ -188,6 +188,7 @@ struct quickroom { long QRnumber; /* Globally unique room number */ char QRorder; /* Sort key for room listing order */ unsigned QRflags2; /* Additional flags */ + int QRdefaultview; /* How to display the contents */ }; /* Private rooms are always flagged with QR_PRIVATE. If neither QR_PASSWORDED @@ -289,3 +290,11 @@ struct floor { #endif #endif /* CITADEL_H */ + + +/* + * Views + */ +#define VIEW_BBS 0 /* Traditional Citadel BBS view */ +#define VIEW_MAILBOX 1 /* Mailbox summary */ +#define VIEW_ADDRESSBOOK 2 /* Address book view */ diff --git a/citadel/citserver.c b/citadel/citserver.c index d543bba20..c96ab9f57 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -158,7 +158,7 @@ void RemoveContext (struct CitContext *con) if (con==NULL) { lprintf(5, "WARNING: RemoveContext() called with NULL!\n"); return; - } + } /* Remove the context from the global context list. This needs * to get done FIRST to avoid concurrency problems. It is *vitally* @@ -170,16 +170,16 @@ void RemoveContext (struct CitContext *con) ToFree = ContextList; ContextList = ContextList->next; --num_sessions; - } + } else { for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { if (ptr->next == con) { ToFree = ptr->next; ptr->next = ptr->next->next; --num_sessions; - } } } + } end_critical_section(S_SESSION_TABLE); if (ToFree == NULL) { @@ -341,11 +341,11 @@ void cmd_info(void) { char CtdlCheckExpress(void) { if (CC->FirstExpressMessage == NULL) { return(' '); - } + } else { return('*'); - } } +} void cmd_time(void) { @@ -374,23 +374,26 @@ static int hostnames_match(const char *realname, const char *testname) { struct hostent *he; int retval = 0; - if (!strcasecmp(realname, testname)) - return 1; + if (!strcasecmp(realname, testname)) { + return(1); + } #ifdef HAVE_NONREENTRANT_NETDB begin_critical_section(S_NETDB); #endif - if ((he = gethostbyname(testname)) != NULL) - if (!strcasecmp(realname, he->h_name)) + if ((he = gethostbyname(testname)) != NULL) { + if (!strcasecmp(realname, he->h_name)) { retval = 1; + } + } #ifdef HAVE_NONREENTRANT_NETDB end_critical_section(S_NETDB); #endif return retval; - } +} /* * check a hostname against the public_clients file @@ -414,12 +417,12 @@ int is_public_client(char *where) if (hostnames_match(where,buf)) { fclose(fp); return(1); - } } + } fclose(fp); return(0); - } +} /* @@ -515,25 +518,25 @@ void cmd_mesg(char *mname) if (strlen(targ)==0) { cprintf("%d '%s' not found.\n",ERROR,mname); return; - } + } mfp = fopen(targ,"r"); if (mfp==NULL) { cprintf("%d Cannot open '%s': %s\n", ERROR,targ,strerror(errno)); return; - } + } cprintf("%d %s\n",LISTING_FOLLOWS,buf); while (fgets(buf, (SIZ-1), mfp)!=NULL) { buf[strlen(buf)-1] = 0; do_help_subst(buf); cprintf("%s\n",buf); - } + } fclose(mfp); cprintf("000\n"); - } +} /* @@ -552,7 +555,7 @@ void cmd_emsg(char *mname) extract(buf,mname,0); for (a=0; acurr_user, ""); CC->cs_flags = CC->cs_flags|CS_STEALTH; cprintf("%d Authenticated as an internal program.\n",CIT_OK); - } + } else { cprintf("%d Authentication failed.\n",ERROR); lprintf(3, "Warning: ipgm authentication failed.\n"); - } } +} /* @@ -745,7 +748,7 @@ void cmd_down(void) { cprintf("%d Shutting down server. Goodbye.\n", CIT_OK); time_to_die = 1; - } +} /* * Schedule or cancel a server shutdown @@ -759,7 +762,7 @@ void cmd_scdn(char *argbuf) new_state = extract_int(argbuf, 0); if ((new_state == 0) || (new_state == 1)) { ScheduledShutdown = new_state; - } + } cprintf("%d %d\n", CIT_OK, ScheduledShutdown); } @@ -861,11 +864,11 @@ void citproto_begin_session() { "(maximum is %d)\n", ERROR+MAX_SESSIONS_EXCEEDED, config.c_nodename, config.c_maxsessions); - } + } else { cprintf("%d %s Citadel/UX server ready.\n", CIT_OK, config.c_nodename); - } + } } @@ -897,7 +900,7 @@ void do_command_loop(void) { safestrncpy(CC->lastcmdname, cmdbuf, sizeof(CC->lastcmdname) ); time(&CC->lastidle); - } + } if ((strncasecmp(cmdbuf, "ENT0", 4)) && (strncasecmp(cmdbuf, "MESG", 4)) @@ -908,333 +911,335 @@ void do_command_loop(void) { if (!strncasecmp(cmdbuf,"NOOP",4)) { cprintf("%d%cok\n",CIT_OK,CtdlCheckExpress()); - } + } else if (!strncasecmp(cmdbuf,"QUIT",4)) { cprintf("%d Goodbye.\n",CIT_OK); CC->kill_me = 1; - } + } else if (!strncasecmp(cmdbuf,"ASYN",4)) { cmd_asyn(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LOUT",4)) { if (CC->logged_in) logout(CC); cprintf("%d logged out.\n",CIT_OK); - } + } else if (!strncasecmp(cmdbuf,"USER",4)) { cmd_user(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"PASS",4)) { cmd_pass(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"NEWU",4)) { cmd_newu(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"CREU",4)) { cmd_creu(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"SETP",4)) { cmd_setp(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LRMS",4)) { cmd_lrms(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LKRA",4)) { cmd_lkra(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LKRN",4)) { cmd_lkrn(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LKRO",4)) { cmd_lkro(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LZRM",4)) { cmd_lzrm(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"GETU",4)) { cmd_getu(); - } + } else if (!strncasecmp(cmdbuf,"SETU",4)) { cmd_setu(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"GOTO",4)) { cmd_goto(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MSGS",4)) { cmd_msgs(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"WHOK",4)) { cmd_whok(); - } + } else if (!strncasecmp(cmdbuf,"RDIR",4)) { cmd_rdir(); - } + } else if (!strncasecmp(cmdbuf,"MSG0",4)) { cmd_msg0(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MSG2",4)) { cmd_msg2(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MSG3",4)) { cmd_msg3(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MSG4",4)) { cmd_msg4(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"OPNA",4)) { cmd_opna(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"INFO",4)) { cmd_info(); - } + } else if (!strncasecmp(cmdbuf,"SLRP",4)) { cmd_slrp(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"INVT",4)) { cmd_invt_kick(&cmdbuf[5],1); - } + } else if (!strncasecmp(cmdbuf,"KICK",4)) { cmd_invt_kick(&cmdbuf[5],0); - } + } else if (!strncasecmp(cmdbuf,"GETR",4)) { cmd_getr(); - } + } else if (!strncasecmp(cmdbuf,"SETR",4)) { cmd_setr(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"GETA",4)) { cmd_geta(); - } + } else if (!strncasecmp(cmdbuf,"SETA",4)) { cmd_seta(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"ENT0",4)) { cmd_ent0(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"RINF",4)) { cmd_rinf(); - } + } else if (!strncasecmp(cmdbuf,"DELE",4)) { cmd_dele(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"KILL",4)) { cmd_kill(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"CRE8",4)) { cmd_cre8(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MOVE",4)) { cmd_move(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"FORG",4)) { cmd_forg(); - } + } else if (!strncasecmp(cmdbuf,"MESG",4)) { cmd_mesg(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"EMSG",4)) { cmd_emsg(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"GNUR",4)) { cmd_gnur(); - } + } else if (!strncasecmp(cmdbuf,"VALI",4)) { cmd_vali(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"EINF",4)) { cmd_einf(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LIST",4)) { cmd_list(); - } + } else if (!strncasecmp(cmdbuf,"CHEK",4)) { cmd_chek(); - } + } else if (!strncasecmp(cmdbuf,"DELF",4)) { cmd_delf(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MOVF",4)) { cmd_movf(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"NETF",4)) { cmd_netf(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"OPEN",4)) { cmd_open(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"CLOS",4)) { cmd_clos(); - } + } else if (!strncasecmp(cmdbuf,"UOPN",4)) { cmd_uopn(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"UCLS",4)) { cmd_ucls(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"READ",4)) { cmd_read(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"WRIT",4)) { cmd_writ(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"QUSR",4)) { cmd_qusr(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"ECHO",4)) { cmd_echo(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"OIMG",4)) { cmd_oimg(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"MORE",4)) { cmd_more(); - } + } else if (!strncasecmp(cmdbuf,"NDOP",4)) { cmd_ndop(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"NUOP",4)) { cmd_nuop(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"LFLR",4)) { cmd_lflr(); - } + } else if (!strncasecmp(cmdbuf,"CFLR",4)) { cmd_cflr(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"KFLR",4)) { cmd_kflr(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"EFLR",4)) { cmd_eflr(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"IDEN",4)) { cmd_iden(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"IPGM",4)) { cmd_ipgm(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"TERM",4)) { cmd_term(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf,"DOWN",4)) { cmd_down(); - } + } else if (!strncasecmp(cmdbuf,"SCDN",4)) { cmd_scdn(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "UIMG", 4)) { cmd_uimg(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "TIME", 4)) { cmd_time(); - } + } else if (!strncasecmp(cmdbuf, "AGUP", 4)) { cmd_agup(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "ASUP", 4)) { cmd_asup(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "GPEX", 4)) { cmd_gpex(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "SPEX", 4)) { cmd_spex(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "CONF", 4)) { cmd_conf(&cmdbuf[5]); - } + } else if (!strncasecmp(cmdbuf, "SEEN", 4)) { cmd_seen(&cmdbuf[5]); - } + } + + else if (!strncasecmp(cmdbuf, "VIEW", 4)) { + cmd_view(&cmdbuf[5]); + } #ifdef DEBUG_MEMORY_LEAKS else if (!strncasecmp(cmdbuf, "LEAK", 4)) { dump_tracked(); - } + } #endif - else if (!DLoader_Exec_Cmd(cmdbuf)) - { - cprintf("%d Unrecognized or unsupported command.\n", - ERROR); - } + else if (!DLoader_Exec_Cmd(cmdbuf)) { + cprintf("%d Unrecognized or unsupported command.\n", ERROR); + } /* Run any after-each-command outines registered by modules */ PerformSessionHooks(EVT_CMD); diff --git a/citadel/room_ops.c b/citadel/room_ops.c index a2f1224f6..f694c3481 100644 --- a/citadel/room_ops.c +++ b/citadel/room_ops.c @@ -768,7 +768,7 @@ void usergoto(char *where, int display_result, int *retmsgs, int *retnew) CC->quickroom.QRname, new_messages, total_messages); if (display_result) - cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d\n", + cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d|%d\n", CIT_OK, CtdlCheckExpress(), truncated_roomname, new_messages, total_messages, @@ -776,8 +776,8 @@ void usergoto(char *where, int display_result, int *retmsgs, int *retnew) CC->quickroom.QRhighest, vbuf.v_lastseen, rmailflag, raideflag, newmailcount, - CC->quickroom.QRfloor); - + CC->quickroom.QRfloor, + vbuf.v_view); } @@ -984,7 +984,7 @@ void cmd_getr(void) if (CtdlAccessCheck(ac_room_aide)) return; getroom(&CC->quickroom, CC->quickroom.QRname); - cprintf("%d%c%s|%s|%s|%d|%d|%d\n", + cprintf("%d%c%s|%s|%s|%d|%d|%d|%d\n", CIT_OK, CtdlCheckExpress(), @@ -999,7 +999,9 @@ void cmd_getr(void) CC->quickroom.QRflags, (int) CC->quickroom.QRfloor, - (int) CC->quickroom.QRorder); + (int) CC->quickroom.QRorder, + + CC->quickroom.QRdefaultview); } @@ -1200,6 +1202,11 @@ void cmd_setr(char *args) time(&CC->quickroom.QRgen); } + if (num_parms(args) >= 8) { + CC->quickroom.QRdefaultview = extract_int(args, 7); + } + + /* Write the room record back to disk */ lputroom(&CC->quickroom); diff --git a/citadel/serv_vandelay.c b/citadel/serv_vandelay.c index 3e33faa93..0a15b9275 100644 --- a/citadel/serv_vandelay.c +++ b/citadel/serv_vandelay.c @@ -97,6 +97,7 @@ void artv_export_rooms_backend(struct quickroom *qrbuf, void *data) { cprintf("%ld\n", qrbuf->QRnumber); cprintf("%d\n", qrbuf->QRorder); cprintf("%u\n", qrbuf->QRflags2); + cprintf("%d\n", qrbuf->QRdefaultview); getroom(&CC->quickroom, qrbuf->QRname); /* format of message list export is all message numbers output @@ -178,6 +179,7 @@ void artv_export_visits(void) { } cprintf("%u\n", vbuf.v_flags); + cprintf("%d\n", vbuf.v_view); } } @@ -410,6 +412,7 @@ void artv_import_room(void) { client_gets(buf); qrbuf.QRnumber = atol(buf); client_gets(buf); qrbuf.QRorder = atoi(buf); client_gets(buf); qrbuf.QRflags2 = atoi(buf); + client_gets(buf); qrbuf.QRdefaultview = atoi(buf); putroom(&qrbuf); lprintf(7, "Imported room <%s>\n", qrbuf.QRname); /* format of message list export is all message numbers output @@ -457,6 +460,7 @@ void artv_import_visit(void) { if (is_textual_seen) strcpy(vbuf.v_seen, buf); client_gets(buf); vbuf.v_flags = atoi(buf); + client_gets(buf); vbuf.v_view = atoi(buf); put_visit(&vbuf); lprintf(7, "Imported visit %ld/%ld/%ld\n", vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum); diff --git a/citadel/server.h b/citadel/server.h index 519535c13..380ebc3b6 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -409,6 +409,7 @@ struct visit { long v_lastseen; unsigned int v_flags; char v_seen[SIZ]; + int v_view; }; #define V_FORGET 1 /* User has zapped this room */ diff --git a/citadel/techdoc/session.txt b/citadel/techdoc/session.txt index c7d482f50..2aed1cd18 100644 --- a/citadel/techdoc/session.txt +++ b/citadel/techdoc/session.txt @@ -399,6 +399,7 @@ a regular Aide (this makes access checks easy). 9. The number of new Mail messages the user has (useful for alerting the user to the arrival of new mail during a session) 10. The floor number this room resides on + 11. The current "view" for this room (see views.txt for more info) MSGS (get pointers to MeSsaGeS in this room) @@ -660,6 +661,7 @@ and the room aide associated with the current room, can access this command. 3. Various flags (bits) associated with the room (see LKRN cmd above) 4. The floor number on which the room resides 5. The room listing order + 6. The default view for the room (see views.txt) SETR (SET Room attributes) @@ -674,6 +676,7 @@ should be passed the following arguments: 4. "Bump" flag (see below) 5. The floor number on which the room should reside 6. The room listing order + 7. The default view for the room (see views.txt) *Important: You should always use GETR to retrieve the current attributes of the room, then change what you want to change, and then use SETR to write it @@ -1896,8 +1899,14 @@ call QDIR with one parameter, the Internet e-mail address to look up. QDIR returns OK followed by a Citadel address if there is a match, otherwise it returns ERROR+NOT_LOGGED_IN. - + + VIEW (set the VIEW for a room) + + Set the preferred view for the current user in the current room. Please see +views.txt for more information on views. The sole parameter for this command +is the type of view requested. VIEW returns OK on success or ERROR on failure. + ASYN (ASYNchronous message support) Negotiate the use of asynchronous, or unsolicited, protocol messages. The diff --git a/citadel/techdoc/views.txt b/citadel/techdoc/views.txt new file mode 100644 index 000000000..1b02b6317 --- /dev/null +++ b/citadel/techdoc/views.txt @@ -0,0 +1,27 @@ +How "views" work in Citadel +--------------------------- + + (Note: this stuff isn't finished yet; we're still building the framework.) + + + There's no need to be rigid and stupid about how different rooms are presented +in a Citadel client. And we don't enforce things either. But there's a need +to make things look the way the user wants to see them. For example, we might +always choose to see a room full of private mail as a summary (one line per +message) rather than always dumping out the entire contents like we do on a +typical BBS room. An address book room might look better as a tabbed view +or something, rather than as a bunch of messages with vCards attached to them. + + This is why we define "views" for a room. It gives the client software a +hint as to how to display the contents of a room. This is kept on a per-user +basis by storing it in the 'visit' record for a particular room/user +combination. It is visit.v_view and is an integer. Naturally, there also +needs to be a default, for users who have never visited the room before. This +is in the room record as quickroom.QRdefaultview (and is also an integer). + + The values currently defined are: + +#define VIEW_BBS 0 /* Traditional Citadel BBS view */ +#define VIEW_MAILBOX 1 /* Mailbox summary */ +#define VIEW_ADDRESSBOOK 2 /* Address book view */ + diff --git a/citadel/user_ops.c b/citadel/user_ops.c index 9c1ade6fb..f5d6bd006 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -229,6 +229,12 @@ void CtdlGetRelationship(struct visit *vbuf, sizeof(struct visit) : cdbvisit->len)); cdb_free(cdbvisit); } + else { + /* If this is the first time the user has seen this room, + * set the view to be the default for the room. + */ + vbuf->v_view = rel_room->QRdefaultview; + } /* Set v_seen if necessary */ if (vbuf->v_seen[0] == 0) { @@ -1420,3 +1426,24 @@ int NewMailCount() return (num_newmsgs); } + + +/* + * Set the preferred view for the current user/room combination + */ +void cmd_view(char *cmdbuf) { + int requested_view; + struct visit vbuf; + + if (CtdlAccessCheck(ac_logged_in)) { + return; + } + + requested_view = extract_int(cmdbuf, 0); + + CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom); + vbuf.v_view = requested_view; + CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom); + + cprintf("%d ok\n", CIT_OK); +} diff --git a/citadel/user_ops.h b/citadel/user_ops.h index ad9fdc4b1..13a7f5b9a 100644 --- a/citadel/user_ops.h +++ b/citadel/user_ops.h @@ -32,6 +32,7 @@ void cmd_chek (void); void cmd_qusr (char *who); void cmd_agup (char *cmdbuf); void cmd_asup (char *cmdbuf); +void cmd_view (char *cmdbuf); int NewMailCount(void); void put_visit(struct visit *newvisit); void CtdlGetRelationship(struct visit *vbuf, -- 2.30.2