/*
*
* (c) COPYRIGHT MIT and INRIA, 1996.
* Please first read the full copyright statement in file COPYRIGHT.
*
*/
/* AHTBridge.c
* INTERFACE BRIDGE TO XT, LIBWWW, and AMAYA
*
* (c) COPYRIGHT
* Please first read the full copyright statement in the file COPYRIGH.
*
* This module implments the callback setup and handlers between
* the Xt, libwww, and Amaya procedures
*
* History:
*
*/
#define EXPORT extern
#include "amaya.h"
#include "AHTBridge_f.h"
#include "AHTFWrite_f.h"
#include "query_f.h"
#include "answer_f.h"
#ifdef WWW_XWINDOWS
/* Amaya's X appcontext */
extern XtAppContext app_cont;
#endif
#ifndef HACK_WWW
extern HTEventCallback *HTEvent_Retrieve (SOCKET, SockOps, HTRequest ** arp);
#endif
/*
* Private functions
*/
#ifdef __STDC__
static void RequestKillReadXtevent (AHTReqContext *);
static void RequestKillWriteXtevent (AHTReqContext *);
static void RequestKillExceptXtevent (AHTReqContext *);
#else
static void RequestKillReadXtevent ();
static void RequestKillWriteXtevent ();
static void RequestKillExceptXtevent ();
#endif
/*
* Private variables
*/
/*
* this set of SockOps map our WinSock "socket event SockOps" into
* our read and write sets. Note that under the canonical Unix model,
* a non-blocking socket passed to an accept() call will appear as readable,
* whilst a non-blocking call to connect() will appear as writeable. In add.
* if the connection has been closed, the socket will appear readable under
* BSD Unix semantics
*/
static const SockOps ReadBits = FD_READ | FD_ACCEPT | FD_CLOSE;
static const SockOps WriteBits = FD_WRITE | FD_CONNECT;
static const SockOps ExceptBits = FD_OOB;
/*
* Private functions
*/
/*--------------------------------------------------------------------
AHTCallback_bridge
Callback that acts as a bridge between X and wwwlib.
This function is equivalent to the library's __DoCallback()
function, but with a different API, to conform to Xt's event loop
specifications. For more info, cf. the library's HTEvntrg.c module.
-------------------------------------------------------------------*/
#ifdef __STDC__
XtInputCallbackProc AHTCallback_bridge (caddr_t cd, int *s, XtInputId * id)
#else
XtInputCallbackProc AHTCallback_bridge (cd, s, id)
caddr_t cd;
int *s;
XtInputId *id;
#endif /* __STDC__ */
/** JK: 26/Dec/96: Took out this code as Cextract has problems to
generate a prototype when there are 2 imbricated ifdefs. ***/
#ifdef 0
/* Windows prototype */
/* some winproc someday? */
LONG AHTCallback_bridge (caddr_t cd, int *s)
#endif /* !WWW_XWINDOWS */
{
int status;
HTRequest *rqp = NULL;
AHTReqContext *me;
SOCKET sock;
SockOps ops=0;
/* Libwww 5.0a does not take into account the ops parameter
for this function call */
#ifdef HACK_WWW
HTEventCallback *cbf;
#else
HTEventCallback *cbf = (HTEventCallback *) __RetrieveCBF (*s, ops, &rqp);
#endif
me = HTRequest_context (rqp);
if (THD_TRACE)
fprintf (stderr, "AHTBridge: Processing url %s \n", me->urlName);
#ifdef WWW_XWINDOWS
switch ((XtInputId) cd)
{
case XtInputReadMask:
ops = me->read_ops;
ops = FD_READ;
break;
case XtInputWriteMask:
ops = me->write_ops;
ops = FD_WRITE;
break;
case XtInputExceptMask:
ops = me->except_ops;
ops = FD_OOB;
break;
} /* switch */
#endif /* WWW_XWINDOWS */
/*
* Liberate the input, so that when a pending socket is activated,
* the socket status will be ... available
*
* verify if I can CHKR_LIMIT this to the unregister function
* does not look so
*
* although it makes no sense, callbacks can be null
*/
if (!cbf || !rqp || rqp->priority == HT_PRIORITY_OFF)
{
if (THD_TRACE)
HTTrace ("Callback.... No callback found\n");
/* put some more code to correctly destroy this request */
return (0);
}
me->reqStatus = HT_BUSY;
if ((status = (*cbf) (*s, rqp, ops)) != HT_OK)
HTTrace ("Callback.... received != HT_OK");
/* Several states can happen after this callback. They
* are indicated by the me->reqStatus structure member and
* the fds external variables. The following lines examine
* the states and correspondly update the Xt event register
*
* Regarding the me->reqStatus member, we have the following
* possible states:
*
* HT_BUSY: Request has blocked
* HT_WAITING: Request has been reissued
* HT_ABORT: Request has been stopped
* HT_END: Request has ended
*/
/* Has the request been stopped?
* we verify if the request exists. If it has ended, me will have
* a reqStatus with an HT_END value */
/* Was the stop button pressed? */
#ifdef WWW_XWINDOWS
if (me->reqStatus == HT_ABORT)
{
me->reqStatus = HT_WAITING;
StopRequest (me->docid);
if (THD_TRACE)
fprintf (stderr, "(BF) removing Xtinput %lu !RWE (Stop buttonl), sock %d\n", me->read_xtinput_id, sock);
return (0);
}
#endif /* WWW_XWINDOWS */
/* the request is being reissued */
if (me->reqStatus == HT_WAITING)
{
/*
* (1) The old request has ended and the library
* assigned the old socket number to a pending
* request.
*
* (2) The request has been reissued after an
* authentication or redirection directive and
* we are using the same old socket number.
*/
if (THD_TRACE)
fprintf (stderr, "*** detected a reissue of request \n");
return (0);
}
/* verify if the request is still alive !! */
if ((me->request->net == (HTNet *) NULL) || (me->reqStatus == HT_END || me->reqStatus == HT_ERR))
{
/* the socket is now being used by a different request, so the request has ended */
#ifdef WWW_XWINDOWS
if (THD_TRACE)
fprintf (stderr, "(BF) removing Xtinput %lu !RWE, sock %d (Request has ended)\n", *id, *s);
#endif
if ((me->mode & AMAYA_ASYNC) || (me->mode & AMAYA_IASYNC))
{
AHTPrintPendingRequestStatus (me->docid, YES);
AHTReqContext_delete (me);
}
else if (me->reqStatus != HT_END && HTError_hasSeverity (HTRequest_error (me->request), ERR_NON_FATAL))
me->reqStatus = HT_ERR;
return (0);
}
me->reqStatus = HT_WAITING;
return (0);
}
/*----------------------------------------------------------------
Add_NewSocket_to_Loop
This function is called whenever a socket is available
for a request. It prepares Xt to handle the
asynchronous data requests.
----------------------------------------------------------------*/
#ifdef __STDC__
int Add_NewSocket_to_Loop (HTRequest * request, HTAlertOpcode op, int msgnum, const char *dfault, void *input, HTAlertPar * reply)
#else
int Add_NewSocket_to_Loop (request, op, msgnum, dfault, input, reply)
HTRequest *request;
HTAlertOpcode op;
int msgnum;
const char *dfault;
void *input;
HTAlertPar *reply;
#endif /* __STDC__ */
{
SOCKET req_socket;
AHTReqContext *me = HTRequest_context (request);
if (me->reqStatus == HT_NEW_PENDING)
{
/* we are opening a pending request */
if ((me->output = fopen (me->outputfile, "w")) == NULL)
{
me->outputfile[0] = '\0'; /* file could not be opened */
TtaSetStatus (me->docid, 1, TtaGetMessage (AMAYA, AM_CANNOT_CREATE_FILE),
me->outputfile);
me->reqStatus = HT_ERR;
return (HT_ERROR);
}
if (THD_TRACE)
fprintf (stderr, "Add_NewSocket_to_Loop: Activating pending %s . Open fd %d\n", me->urlName, (int) me->output);
HTRequest_setOutputStream (me->request,
AHTFWriter_new (me->request, me->output, YES));
}
me->reqStatus = HT_WAITING;
if (THD_TRACE)
fprintf (stderr, "(Activating a pending request\n");
/* reusing this function to save on file descriptors */
return (HT_OK);
/* get the socket number associated to the request */
req_socket = HTNet_socket (request->net);
if (req_socket == INVSOC)
{
/* this should never be true */
return (HT_ERROR);
}
/* add the input */
#ifdef WWW_XWINDOWS
me->write_xtinput_id =
XtAppAddInput (app_cont, req_socket, (XtPointer) XtInputWriteMask,
(XtInputCallbackProc) AHTCallback_bridge, NULL);
if (THD_TRACE)
fprintf (stderr, "(BT) adding Xtinput %lu Socket %d W \n", me->write_xtinput_id, req_socket);
if (me->write_xtinput_id == (XtInputId) NULL)
{
TtaSetStatus (me->docid, 1, TtaGetMessage (AMAYA, AM_XT_ERROR), me->urlName);
/* I still need to add some error treatment here, to liberate memory */
return (HT_ERROR);
}
#endif /* WWW_XWINDOWS */
return (HT_OK);
}
/*
* This function is called whenever a socket is available
* for a request. It the necessary events to the Xt
* A small interface to the HTLoadAnchor libwww function.
* It prepares Xt to handle the asynchronous data requests.
*/
#ifdef __STDC__
int AHTEvent_register (SOCKET sock, HTRequest * rqp, SockOps ops, HTEventCallback * cbf, HTPriority p)
#else
int AHTEvent_register (sock, rqp, ops, cbf, p)
SOCKET sock;
HTRequest *rqp;
SockOps ops;
HTEventCallback *cbf;
HTPriority p;
#endif /* __STDC__ */
{
AHTReqContext *me;
int status;
if (sock == INVSOC)
return (0);
/* get the request associated to the socket number */
if ((status = HTEventrg_register (sock, rqp, ops,
cbf, p)) != HT_OK)
return (status);
if (rqp)
{
me = HTRequest_context (rqp);
/* verify if we need to open the fd */
if (me->reqStatus == HT_NEW_PENDING)
{
/* we are opening a pending request */
if ((me->output = fopen (me->outputfile, "w")) == NULL)
{
me->outputfile[0] = '\0'; /* file could not be opened */
TtaSetStatus (me->docid, 1, TtaGetMessage (AMAYA, AM_CANNOT_CREATE_FILE),
me->outputfile);
me->reqStatus = HT_ERR;
return (HT_ERROR);
}
HTRequest_setOutputStream (me->request,
AHTFWriter_new (me->request, me->output, YES));
me->reqStatus = HT_WAITING;
if (THD_TRACE)
fprintf (stderr, "AHTEvent_register: Activating pending request url %s, fd %d\n", me->urlName, (int) me->output);
}
if (THD_TRACE)
fprintf (stderr, "AHTEvent_register: url %s, sock %d, ops %lu \n",
me->urlName, sock, ops);
/* add the input */
if (me->reqStatus == HT_NEW)
me->reqStatus = HT_WAITING;
if (ops & ReadBits)
{
me->read_ops = ops;
#ifdef WWW_XWINDOWS
if (me->read_xtinput_id)
XtRemoveInput (me->read_xtinput_id);
me->read_xtinput_id =
XtAppAddInput (app_cont,
sock,
(XtPointer) XtInputReadMask,
(XtInputCallbackProc) AHTCallback_bridge,
(XtPointer) XtInputReadMask);
if (THD_TRACE)
fprintf (stderr, "(BT) adding Xtinput %lu Socket %d R\n",
me->read_xtinput_id, sock);
#endif /* WWW_XWINDOWS */
}
if (ops & WriteBits)
{
me->write_ops = ops;
#ifdef WWW_XWINDOWS
if (me->write_xtinput_id)
XtRemoveInput (me->write_xtinput_id);
me->write_xtinput_id = XtAppAddInput (app_cont, sock,
(XtPointer) XtInputWriteMask,
(XtInputCallbackProc) AHTCallback_bridge,
(XtPointer) XtInputWriteMask);
if (THD_TRACE)
fprintf (stderr, "(BT) adding Xtinput %lu Socket %d W\n",
me->write_xtinput_id, sock);
#endif /* WWW_XWINDOWS */
}
if (ops & ExceptBits)
{
me->except_ops = ops;
#ifdef WWW_XWINDOWS
if (me->except_xtinput_id)
XtRemoveInput (me->except_xtinput_id);
me->except_xtinput_id = XtAppAddInput (app_cont, sock,
(XtPointer) XtInputExceptMask,
(XtInputCallbackProc) AHTCallback_bridge,
(XtPointer) XtInputExceptMask);
if (THD_TRACE)
fprintf (stderr, "(BT) adding Xtinput %lu Socket %d E\n", me->except_xtinput_id, sock);
#endif /* WWW_XWINDOWS */
}
}
#if 0
if (me->xtinput_id == (XtInputId) NULL)
{
TtaSetStatus (me->docid, 1, TtaGetMessage (AMAYA, AM_XT_ERROR), me->urlName);
/* I still need to add some error treatment here, to liberate memory */
return (HT_ERROR);
}
#endif
return (status);
}
#ifdef __STDC__
int AHTEvent_unregister (SOCKET sock, SockOps ops)
#else
int AHTEvent_unregister (sock, ops)
SOCKET sock;
SockOps ops;
#endif /* __STDC__ */
{
int status;
HTRequest *rqp = NULL;
AHTReqContext *me;
/* Libwww 4.1 does not take into account the third parameter
** for this function call */
HTEventCallback *cbf = (HTEventCallback *) __RetrieveCBF (sock, (SockOps) NULL, &rqp);
#ifdef WWW_XWINDOWS
if (cbf)
{
if (rqp)
{
me = HTRequest_context (rqp);
if (ops & ReadBits)
RequestKillReadXtevent (me);
if (ops & WriteBits)
RequestKillWriteXtevent (me);
if (ops & ExceptBits)
RequestKillExceptXtevent (me);
}
}
status = HTEventrg_unregister (sock, ops);
#endif /* WWW_XWINDOWS */
return (status);
}
#ifdef __STDC__
void RequestKillAllXtevents (AHTReqContext * me)
#else
void RequestKillAllXtevents (me)
AHTReqContext *me;
#endif /* __STDC__ */
{
#ifdef WWW_XWINDOWS
if (THD_TRACE)
fprintf (stderr, "Request_kill: Clearing Xtinputs\n");
RequestKillReadXtevent (me);
RequestKillWriteXtevent (me);
RequestKillExceptXtevent (me);
#endif /* WWW_XWINDOWS */
}
#ifdef __STDC__
static void RequestKillReadXtevent (AHTReqContext * me)
#else
static void RequestKillReadXtevent (me)
AHTReqContext *me;
#endif /* __STDC__ */
{
#ifdef WWW_XWINDOWS
if (me->read_xtinput_id)
{
if (THD_TRACE)
fprintf (stderr, "Request_kill: Clearing Read Xtinputs%lu\n", me->read_xtinput_id);
XtRemoveInput (me->read_xtinput_id);
me->read_xtinput_id = (XtInputId) NULL;
}
#endif /* WWW_XWINDOWS */
}
#ifdef __STDC__
static void RequestKillWriteXtevent (AHTReqContext * me)
#else
static void RequestKillWriteXtevent (me)
AHTReqContext *me;
#endif /* __STDC__ */
{
#ifdef WWW_XWINDOWS
if (me->write_xtinput_id)
{
if (THD_TRACE)
fprintf (stderr, "Request_kill: Clearing Write Xtinputs %lu\n", me->write_xtinput_id);
XtRemoveInput (me->write_xtinput_id);
me->write_xtinput_id = (XtInputId) NULL;
}
#endif /* WWW_XWINDOWS */
}
#ifdef __STDC__
static void RequestKillExceptXtevent (AHTReqContext * me)
#else
static void RequestKillExceptXtevent (me)
AHTReqContext *me;
#endif /* __STDC__ */
{
#ifdef WWW_XWINDOWS
if (me->except_xtinput_id)
{
if (THD_TRACE)
fprintf (stderr, "Request_kill: Clearing Except Xtinputs %lu\n", me->except_xtinput_id);
XtRemoveInput (me->except_xtinput_id);
me->except_xtinput_id = (XtInputId) NULL;
}
#endif /* WWW_XWINDOWS */
}
Webmaster