$Log$
+ Revision 621.10 2004/06/09 03:54:07 ajc
+ * The scheduler can now "wake up" a session to deliver async messages.
+ * Renumbered the "instant msgs waiting" message and changed its usage
+
Revision 621.9 2004/06/07 22:12:19 ajc
* Removed network/filterlist network/mailinglists network/rnews.xref
because none of these are used anymore.
Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
* Initial CVS import
-
/* Run any after-each-command routines registered by modules */
PerformSessionHooks(EVT_CMD);
}
+
+
+/*
+ * This loop performs all asynchronous functions.
+ */
+void do_async_loop(void) {
+ PerformSessionHooks(EVT_ASYNC);
+}
void CtdlAllocUserData(unsigned long requested_sym, size_t num_bytes);
void CtdlReallocUserData(unsigned long requested_sym, size_t num_bytes);
void do_command_loop(void);
+void do_async_loop(void);
void begin_session(struct CitContext *con);
void citproto_begin_session(void);
void GenerateRoomDisplay(char *real_room,
#define MESSAGE_NOT_FOUND 75
#define ASYNC_MSG 900
-#define ASYNC_GEXP 01
+#define ASYNC_GEXP 02
#define QR_PERMANENT 1 /* Room does not purge */
#define QR_INUSE 2 /* Set if in use, clear if avail */
if (CC->FirstExpressMessage == NULL) return;
cprintf("%d instant msg\n", ASYNC_MSG + ASYNC_GEXP);
- cmd_gexp("");
}
/*
}
findend->next = newmsg;
}
+
+ /* If the target context is a session which can handle asynchronous
+ * messages, go ahead and set the flag for that.
+ */
+ if (ccptr->is_async) {
+ ccptr->async_waiting = 1;
+ if (ccptr->state == CON_IDLE) {
+ ccptr->state = CON_READY;
+ }
+ }
}
CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an instant message");
CtdlRegisterProtoHook(cmd_dexp, "DEXP", "Disable instant messages");
CtdlRegisterProtoHook(cmd_reqt, "REQT", "Request client termination");
- CtdlRegisterSessionHook(cmd_gexp_async, EVT_CMD);
+ CtdlRegisterSessionHook(cmd_gexp_async, EVT_ASYNC);
CtdlRegisterSessionHook(delete_instant_messages, EVT_STOP);
CtdlRegisterXmsgHook(send_instant_message, XMSG_PRI_LOCAL);
return "$Id$";
void CtdlRegisterServiceHook(int tcp_port,
char *sockpath,
void (*h_greeting_function) (void),
- void (*h_command_function) (void) )
+ void (*h_command_function) (void),
+ void (*h_async_function) (void)
+ )
{
struct ServiceFunctionHook *newfcn;
char message[SIZ];
newfcn->sockpath = sockpath;
newfcn->h_greeting_function = h_greeting_function;
newfcn->h_command_function = h_command_function;
+ newfcn->h_async_function = h_async_function;
if (sockpath != NULL) {
newfcn->msock = ig_uds_server(sockpath, config.c_maxsessions);
void CtdlUnregisterServiceHook(int tcp_port, char *sockpath,
void (*h_greeting_function) (void),
- void (*h_command_function) (void) )
+ void (*h_command_function) (void),
+ void (*h_async_function) (void)
+ )
{
struct ServiceFunctionHook *cur, *p;
strcmp(sockpath, cur->sockpath)) &&
h_greeting_function == cur->h_greeting_function &&
h_command_function == cur->h_command_function &&
+ h_async_function == cur->h_async_function &&
tcp_port == cur->tcp_port) {
close(cur->msock);
if (sockpath) {
void CtdlRegisterServiceHook(int tcp_port,
char *sockpath,
void (*h_greeting_function) (void),
- void (*h_command_function) (void) ) ;
+ void (*h_command_function) (void),
+ void (*h_async_function) (void)
+ ) ;
void CtdlUnregisterServiceHook(int tcp_port,
char *sockpath,
void (*h_greeting_function) (void),
- void (*h_command_function) (void) ) ;
+ void (*h_command_function) (void),
+ void (*h_async_function) (void)
+ ) ;
#endif /* SERV_EXTENSIONS_H */
char *serv_imap_init(void)
{
CtdlRegisterServiceHook(config.c_imap_port,
- NULL, imap_greeting, imap_command_loop);
+ NULL, imap_greeting, imap_command_loop, NULL);
CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP);
return "$Id$";
}
CtdlRegisterServiceHook(config.c_pop3_port,
NULL,
pop3_greeting,
- pop3_command_loop);
+ pop3_command_loop,
+ NULL);
CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP);
return "$Id$";
}
CtdlRegisterServiceHook(config.c_smtp_port, /* On the net... */
NULL,
smtp_greeting,
- smtp_command_loop);
+ smtp_command_loop,
+ NULL);
CtdlRegisterServiceHook(0, /* ...and locally */
"lmtp.socket",
lmtp_greeting,
- smtp_command_loop);
+ smtp_command_loop,
+ NULL);
smtp_init_spoolout();
CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
char lastcmdname[5]; /* name of last command executed */
unsigned cs_flags; /* miscellaneous flags */
void (*h_command_function) (void) ; /* service command function */
+ void (*h_async_function) (void) ; /* do async msgs function */
int is_async; /* Nonzero if client accepts async msgs */
+ int async_waiting; /* Nonzero if there are async msgs waiting */
+ int input_waiting; /* Nonzero if there is client input waiting */
/* feeping creaturisms... */
int cs_clientdev; /* client developer ID */
#define EVT_SETPASS 5 /* Setting or changing password */
#define EVT_CMD 6 /* Called after each server command */
#define EVT_RWHO 7 /* An RWHO command is being executed */
+#define EVT_ASYNC 8 /* Doing asynchronous messages */
#define EVT_TIMER 50 /* Timer events are called once per minute
and are not tied to any session */
char *sockpath;
void (*h_greeting_function) (void) ;
void (*h_command_function) (void) ;
+ void (*h_async_function) (void) ;
int msock;
};
extern struct ServiceFunctionHook *ServiceHookTable;
CtdlRegisterServiceHook(0,
"citadel.socket",
citproto_begin_session,
- do_command_loop);
+ do_command_loop,
+ do_async_loop);
/*
* Bind the server to our favorite TCP port (usually 504).
CtdlRegisterServiceHook(config.c_port_number,
NULL,
citproto_begin_session,
- do_command_loop);
+ do_command_loop,
+ do_async_loop);
/*
* Load any server-side extensions available here.
con->client_socket = ssock;
con->h_command_function =
serviceptr->h_command_function;
+ con->h_async_function =
+ serviceptr->h_async_function;
/* Determine whether local socket */
if (serviceptr->sockpath != NULL)
for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
if ( (FD_ISSET(ptr->client_socket, &readfds))
&& (ptr->state != CON_EXECUTING) ) {
+ ptr->input_waiting = 1;
if (!bind_me) {
bind_me = ptr; /* I choose you! */
bind_me->state = CON_EXECUTING;
end_critical_section(S_SESSION_TABLE);
SKIP_SELECT: end_critical_section(S_I_WANNA_SELECT);
- /* We're bound to a session, now do *one* command */
+ /* We're bound to a session */
if (bind_me != NULL) {
become_session(bind_me);
- CC->h_command_function();
+
+ /* If the client has sent a command, execute it. */
+ if (CC->input_waiting) {
+ CC->h_command_function();
+ CC->input_waiting = 0;
+ }
+
+ /* If there are asynchronous messages waiting and the
+ * client supports it, do those now */
+ if ((CC->is_async) && (CC->async_waiting)
+ && (CC->h_async_function != NULL)) {
+ CC->h_async_function();
+ CC->async_waiting = 0;
+ }
+
force_purge = CC->kill_me;
become_session(NULL);
bind_me->state = CON_IDLE;
any time:
- 901 (instant message arriving)
+ 902 (instant message arriving)
- One or more instant messages have arrived for this client. When the client
-receives this message, it MUST act as if it just sent a GEXP command (the data
-following the 901 message WILL be a LISTING_FOLLOWS data transfer; in fact,
-the current implementation simply executes a GEXP command internally).
+ One or more instant messages have arrived for this client.