home *** CD-ROM | disk | FTP | other *** search
/ WordPerfect for Linux Bible / WP4LinuxBible.iso / sdk / wpx / code / wt / wtcomm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-06-25  |  27.8 KB  |  943 lines

  1.  
  2. /* SOURCE FILE *****************************************************
  3.  * WTCOMM.C  -  Writing Tools Communication interface
  4.  *******************************************************************
  5.  *    Copyright (C) 1992, 1993 WordPerfect Corp., All Rights Reserved
  6.  *******************************************************************/
  7.  
  8. #include "wtapi.h"
  9. #include "wtcomm.h"
  10.  
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include <limits.h>       /* for PIPE_BUF */
  14. #ifdef LINUX
  15. #include <linux/limits.h> /* for PIPE_BUF */
  16. #endif
  17. #include <signal.h>
  18. #include <sys/errno.h>
  19. #include <Xm/Xm.h>
  20.  
  21. /***** DEFINE THE APPROPRIATE ITEM TO USE THE CODE FOR WRITING *****/
  22. /***** TOOL SERVERS OR WRITING TOOL CLIENTS (OR BOTH).         *****/
  23. /* define WTAPI_SERVER */
  24. /* define WTAPI_CLIENT */
  25.  
  26.  
  27. /*----------------------------------------------------------
  28.     External Variables
  29. ------------------------------------------------------------*/
  30. extern int errno;
  31.  
  32. /*----------------------------------------------------------
  33.     External Functions
  34. ------------------------------------------------------------*/
  35. void quitTool(char *);
  36.  
  37. /*----------------------------------------------------------
  38.     Internal Variables
  39. ------------------------------------------------------------*/
  40. #ifdef WTAPI_CLIENT
  41. WTCOMM commHandle;    /* conversation/comm. handle */
  42. #else
  43. extern WTCOMM comm_id;
  44. #endif /* WTAPI_CLIENT */
  45. static char *SndMessage;    /* message to send */
  46. static char *RcvMessage;    /* received message */
  47. static short MsgLen;        /* number of bytes in message */
  48. static short NeedModalReply = 0;    /* waiting for modal reply? */
  49. static short NeedRequestReply = 0;    /* waiting for reply to request? */
  50. static void (*oldsigfunc)();
  51.  
  52. /*----------------------------------------------------------
  53.     Internal Functions
  54. ------------------------------------------------------------*/
  55. MSG_ERRS ReceiveMsg(WTPIPE, char *);
  56. MSG_ERRS SendMsg(WTPIPE, char *, char *, MSG_TYPE, char *, int);
  57. MSG_ERRS SendMsgModal(WTPIPE, char *, char *, MSG_TYPE, char *, int);
  58. MSG_ERRS SendRequestAct(WTPIPE,char *,char *,MSG_TYPE,char *,int,FUNCP);
  59. static PIPE_ERRS readpipe(int, char **, short *);
  60. static PIPE_ERRS writepipe(int, char *, short);
  61. static MSG_ERRS DoSend(WTPIPE,char *,char *,MSG_TYPE,char *,int,SEND_TYPE);
  62.  
  63. #ifdef WTAPI_CLIENT
  64. WTCOMM WtConnect(Widget, char *);
  65. void WtDisconnect(WTCOMM);
  66. static void WtClMsgReceived(XtPointer, int *, XtInputId *);
  67. static WTSTATUS wtClReceiveMsg(char *, char *);
  68. #endif /* WTAPI_CLIENT */
  69.  
  70. #ifdef WTAPI_SERVER
  71. WTCOMM WTInitComm(Widget, char *, int, int);
  72. void WTCloseComm(WTCOMM);
  73. static void WtTlMsgReceived(XtPointer, int *, XtInputId *);
  74. static WTSTATUS wtTlReceiveMsg(char *, char *);
  75. #endif /* WTAPI_SERVER */
  76.  
  77. /*COMMENT***************************************************
  78. ;readpipe
  79. Title:    Read a message from a pipe.
  80. In:        fd - file descriptor to read from
  81. Out:    mess - pointer to message (USER MUST FREE THIS MEMORY!!!)
  82.         cnt - number of bytes in message
  83. Xin:    none
  84. Xout:    none
  85. Return:    status of read
  86. Notes:  THE VARIABLE TYPE OF msgsiz MUST NOT CHANGE!!!
  87. ***********************************************************/
  88. static PIPE_ERRS readpipe(int fd, char **mess, short *cnt)
  89. {
  90.     short msgsiz = 0;    /* number of bytes in message on pipe */
  91.     char *msgbuf;        /* pointer to buffer to read message into */
  92.     int rdcnt = 0;        /* number of bytes read from pipe */
  93.  
  94.     *mess = 0;
  95.     *cnt = 0;
  96.     /*
  97.      * Read the size of the next message from the pipe.
  98.      */
  99.     while ((rdcnt = read(fd, (char *)&msgsiz, sizeof(msgsiz))) == -1) {
  100.         if (errno != EINTR) {        /* were we interrupted? */
  101.             return(PIPE_ERROR);        /* no, return error */
  102.         }                            /* yes, do read again */
  103.     }
  104.     if (rdcnt != sizeof(msgsiz)) {
  105.         return(PIPE_ERROR);        /* return error */
  106.     }
  107.     /*
  108.      * Allocate space and read the next message from the pipe.
  109.      */
  110.     if (!(msgbuf = (char *)malloc(msgsiz))) {
  111.         return(PIPE_NOMEM);        /* return error */
  112.     }
  113.     while ((rdcnt = read(fd, msgbuf, msgsiz)) == -1) {
  114.         if (errno != EINTR) {        /* were we interrupted? */
  115.             free(msgbuf);            /* no, return error */
  116.             return(PIPE_ERROR);
  117.         }                            /* yes, do read again */
  118.     }
  119.     if (!rdcnt) {            /* partner die or close pipe? */
  120.         free(msgbuf);        /* yes */
  121.         return(PIPE_DOWN);
  122.     }
  123.     if (rdcnt != msgsiz) {        /* read correct number of bytes? */
  124.         free(msgbuf);            /* no, return error */
  125.         return(PIPE_ERROR);
  126.     }
  127.     *mess = msgbuf;        /* user must free this memory */
  128.     *cnt = msgsiz;
  129.     return(PIPE_OK);
  130. } /* readpipe */
  131.  
  132. /*COMMENT***************************************************
  133. ;writepipe
  134. Title:    Write a message to a pipe.
  135. In:        fd - file descriptor to write to
  136.         mess - pointer to message
  137.         cnt - number of bytes in message
  138. Out:    none
  139. Xin:    none
  140. Xout:    none
  141. Return:    status of write
  142. Notes:  THE VARIABLE TYPE OF msgsiz MUST NOT CHANGE!!!
  143. ***********************************************************/
  144. static PIPE_ERRS writepipe(int fd, char *mess, short cnt)
  145. {
  146.     short msgsiz = cnt;    /* number of bytes of message on pipe */
  147.     int wrtcnt = 0;        /* number of bytes written to pipe */
  148.     char *data = NULL;    /* pointer to mess data */
  149.     int remainingsize = 0;
  150.     int sendamount = 0;
  151.  
  152.  
  153.     /*
  154.      * Write the size of the message to the pipe.
  155.      */
  156.     while ((wrtcnt = write(fd, (char *)&msgsiz, sizeof(msgsiz))) == -1) {
  157.         if (errno != EINTR) {        /* were we interrupted? */
  158.             return(PIPE_ERROR);        /* no, return error */
  159.         }                            /* yes, do write again */
  160.     }
  161.     if (wrtcnt != sizeof(msgsiz)) {
  162.         return(PIPE_ERROR);        /* return error */
  163.     }
  164.     /*
  165.      * Write the message to the pipe.
  166.      */
  167.     data = mess;
  168.     remainingsize = (int) msgsiz;
  169.     /* If on a HP700 or SCO UNIX, then you may need to uncomment this line: */
  170.     /* #define PIPE_BUF 4096 */
  171.     while (data && (remainingsize > 0)) {
  172.         if( remainingsize > PIPE_BUF) { /* don't send more than the pipe can handle */
  173.             sendamount = PIPE_BUF;
  174.         } else {
  175.             sendamount = (int) remainingsize;
  176.         }
  177.         while ((wrtcnt = write(fd, data, msgsiz)) == -1) {
  178.             if (errno != EINTR) {        /* were we interrupted? */
  179.                 return(PIPE_ERROR);        /* no, return error */
  180.             }                            /* yes, do write again */
  181.         }
  182.         data += wrtcnt; /* move the pointer past bytes that were sent */
  183.         remainingsize -= wrtcnt;
  184.     }
  185.     return(PIPE_OK);    
  186. } /* writepipe */
  187.  
  188. /*COMMENT***************************************************
  189. ;ReceiveMsg
  190. Title:    Get the next message on the pipe.
  191. In:        pipe - read/write file descriptors
  192.         caller - name of application which called ReceiveMsg()
  193. Out:    none
  194. Xin:    none
  195. Xout:    none
  196. Return:    MSG_OK or error
  197. Notes:
  198. ***********************************************************/
  199. MSG_ERRS ReceiveMsg(WTPIPE pipe, char *caller)
  200. {
  201.     PIPE_ERRS stat;        /* status of pipe read/writes */
  202.     MSG_TYPE msgtype;    /* message type */
  203.     SEND_TYPE sendtype;    /* type of message send */
  204.     char *sender;        /* sender of the message */
  205.     char *body;            /* beginning of body of message */
  206.     short result = MSG_OK;    /* result of a modal send */
  207.     char rbuf[4];
  208.  
  209.     /*
  210.      * Read the next message off the pipe.
  211.      */
  212.     stat = readpipe(pipe.read, &RcvMessage, &MsgLen);
  213.     if ((stat != PIPE_OK) || !RcvMessage) {
  214.         if (RcvMessage) {
  215.             free(RcvMessage);
  216.             RcvMessage = 0;
  217.         }
  218.         return(MSG_CANT_RECEIVE);
  219.     }
  220.     /*
  221.      * Get the message type, send type, and sender and find the beginning
  222.      * of the message body.
  223.      */
  224.     msgtype = RcvMessage[0];
  225.     sendtype = RcvMessage[1];
  226.     sender = &RcvMessage[2];
  227.     body = sender + strlen(sender) + 1;
  228.     /*
  229.      * If this is a REPLY, check to see if it is the REPLY sent in response
  230.      * to a modal send.  If so clear the NeedModalReply flag and return
  231.      * the status.  If not, this REPLY must be a response to SendRequestAct()
  232.      * so clear the NeedRequestReply flag.  This will result in the exit of
  233.      * the loop in SendRequestAct() and it will proceed to handle the reply
  234.      * message.
  235.      */
  236.     if (msgtype == REPLY) {
  237.         if (NeedModalReply) {
  238.             /*
  239.              * If the body of the message is exactly the size of the result
  240.              * variable then assume it is a modal reply and return the
  241.              * result.  Currently all other reply messages are larger than
  242.              * two bytes.
  243.              */
  244.             if ((MsgLen - (body - RcvMessage)) == sizeof(result)) {
  245.                 memcpy((char *)&result, body, sizeof(result));
  246.                 NeedModalReply = 0;            /* clear flag */
  247.                 free(RcvMessage); RcvMessage = 0;
  248.                 return(result);
  249.             }
  250.         } else if (NeedRequestReply) {
  251.             NeedRequestReply = 0;
  252.             /* don't free RcvMessage yet, used in SendRequestAct() */
  253.             return(MSG_OK);
  254.         }
  255.         free(RcvMessage); RcvMessage = 0;
  256.         return(MSG_OK);
  257.     }
  258.     switch (msgtype) {
  259. #ifdef WTAPI_CLIENT
  260.         case WTAPI_TOOL_COMMAND:
  261.             wtClReceiveMsg(sender, body);
  262.             break;
  263.         case WTAPI_TOOL_QUERY:
  264.             wtClReceiveMsg(sender, body);
  265.             break;
  266. #endif /* WTAPI_CLIENT */
  267. #ifdef WTAPI_SERVER
  268.         case WTAPI_CLIENT_COMMAND:
  269.             wtTlReceiveMsg(sender, body);
  270.             break;
  271.         case WTAPI_CLIENT_QUERY:
  272.             wtTlReceiveMsg(sender, body);
  273.             break;
  274. #endif /* WTAPI_SERVER */
  275.         default:
  276.             break;        /* ignore other types of messages */
  277.     }
  278.     /*
  279.      * If send type was modal, return the result of this message.
  280.      */
  281.     if (sendtype == MSG_SEND_MODAL) {
  282.         memcpy(rbuf, (char *)&result, sizeof(result));
  283.         DoSend(pipe, caller, sender, REPLY, rbuf, sizeof(result), MSG_SEND);
  284.     }
  285.     free(RcvMessage); RcvMessage = 0;
  286.     return(MSG_OK);
  287. } /* ReceiveMsg */
  288.  
  289. /*COMMENT***************************************************
  290. ;SendMsg
  291. Title:    Send a message across the pipe.
  292. In:        pipe - read/write file descriptors
  293.         caller - name of application which called SendMsg()
  294.         product - name of product to send message to
  295.         msgtype - message type
  296.         data - body of message
  297.         len - number of bytes in message
  298. Out:    none
  299. Xin:    none
  300. Xout:    none
  301. Return:    MSG_OK or error
  302. Notes:
  303. ***********************************************************/
  304. MSG_ERRS SendMsg(WTPIPE pipe, char *caller, char *product,
  305.     MSG_TYPE msgtype, char *data, int len)
  306. {
  307.     return(DoSend(pipe, caller, product, msgtype, data, len, MSG_SEND));
  308. } /* SendMsg */
  309.  
  310. /*COMMENT***************************************************
  311. ;SendModalMsg
  312. Title:    Send a message across the pipe and wait for a return status.
  313. In:        pipe - read/write file descriptors
  314.         caller - name of application which called SendModalMsg()
  315.         product - name of product to send message to
  316.         msgtype - message type
  317.         data - body of message
  318.         len - number of bytes in message
  319. Out:    none
  320. Xin:    none
  321. Xout:    none
  322. Return:    MSG_OK or error
  323. Notes:
  324. ***********************************************************/
  325. MSG_ERRS SendModalMsg(WTPIPE pipe, char *caller, char *product,
  326.     MSG_TYPE msgtype, char *data, int len)
  327. {
  328.     MSG_ERRS ret;
  329.  
  330.     NeedModalReply = 1;
  331.     ret = DoSend(pipe, caller, product, msgtype, data, len, MSG_SEND_MODAL);
  332.     if (ret != MSG_OK) {
  333.         return(ret);
  334.     }
  335.     /*
  336.      * Loop receiving messages until the REPLY to the modal send is returned.
  337.      */
  338.     while (NeedModalReply) {
  339.         ret = ReceiveMsg(pipe, caller);    /* wait for reply */
  340.         if (ret) {                        /* error receiving reply */
  341.             return(ret);
  342.         }
  343.     }
  344.     return(ret);
  345. } /* SendModalMsg */
  346.  
  347. /*COMMENT***************************************************
  348. ;SendRequestAct
  349. Title:    Send a message across the pipe, wait for a reply, call reply handler
  350. In:        pipe - read/write file descriptors
  351.         caller - name of application which called SendRequestAct()
  352.         product - name of product to send message to
  353.         msgtype - message type
  354.         data - body of message
  355.         len - number of bytes in message
  356.         handler - pointer to routine to process returned message data
  357. Out:    none
  358. Xin:    none
  359. Xout:    none
  360. Return:    MSG_OK or error
  361. Notes:
  362. ***********************************************************/
  363. MSG_ERRS SendRequestAct(WTPIPE pipe, char *caller, char *product,
  364.     MSG_TYPE msgtype, char *data, int len, FUNCP handler)
  365. {
  366.     MSG_ERRS ret;
  367.     char *sender, *mess;
  368.  
  369.     NeedRequestReply = 1;
  370.     ret = SendMsg(pipe, caller, product, msgtype, data, len);
  371.     if (ret) {        /* error sending message */
  372.         return(ret);
  373.     }
  374.     /*
  375.      * Loop receiving messages until the REPLY to the request is returned.
  376.      */
  377.     while (NeedRequestReply) {
  378.         ret = ReceiveMsg(pipe, caller);    /* wait for reply */
  379.         if (ret) {                        /* error receiving reply */
  380.             return(ret);
  381.         }
  382.     }
  383.     /*
  384.      * If caller passed in a handler routine, call that routine passing
  385.      * in the sender name and the body of the message.
  386.      */
  387.     if (handler) {
  388.         sender = &RcvMessage[2];
  389.         mess = sender + strlen(sender) + 1;
  390.         (*handler)(sender, mess);
  391.     }
  392.     return(MSG_OK);
  393. } /* SendRequestAct */
  394.  
  395. /*COMMENT***************************************************
  396. ;DoSend
  397. Title:    Common code for SendMsg() and SendMsgModal().
  398. In:        pipe - read/write file descriptors
  399.         caller - name of application which called DoSend()
  400.         product - name of product to send message to
  401.         msgtype - message type
  402.         data - body of message
  403.         len - number of bytes in message
  404.         sendtype - type of send (MSG_SEND, MSG_SEND_MODAL, MSG_SEND_REQUEST)
  405. Out:    none
  406. Xin:    none
  407. Xout:    none
  408. Return:    MSG_OK or error
  409. Notes:
  410. ***********************************************************/
  411. static MSG_ERRS DoSend(WTPIPE pipe, char *caller, char *product,
  412.     MSG_TYPE msgtype, char *data, int len, SEND_TYPE sendtype)
  413. {
  414.     PIPE_ERRS stat;
  415.     int hdrlen;        /* length of header */
  416.  
  417.     /*
  418.      * Prefix the message type, send type, and name of this sending product
  419.      * (caller) to the message.
  420.      */
  421.     hdrlen = 1 + 1 + strlen(caller) + 1;
  422.     MsgLen = hdrlen + len;
  423.     SndMessage = (char *)malloc(MsgLen);
  424.     if (!SndMessage) {
  425.         return(MSG_NOMEM);
  426.     }
  427.     SndMessage[0] = (char) msgtype;    /* type of message */
  428.     SndMessage[1] = (char) sendtype;    /* type of send */
  429.     strcpy(&SndMessage[2], caller);    /* sending product */
  430.     /*
  431.      * Copy in the message data.
  432.      */
  433.     memcpy(&SndMessage[hdrlen], data, len);
  434.     /*
  435.      * Send the message.
  436.      */
  437.     stat = writepipe(pipe.write, SndMessage, MsgLen);
  438.     free(SndMessage);  SndMessage = 0;
  439.     if (stat != PIPE_OK) {
  440.         return(MSG_CANT_DELIVER);
  441.     }
  442.     return(MSG_OK);
  443. } /* DoSend */
  444.  
  445. #ifdef WTAPI_CLIENT
  446. /*COMMENT***************************************************
  447. ;WtConnect
  448. Title:    Initialize WT Client communication
  449. In:        toplevel - toplevel widget of client
  450.         exepath - full path to executable
  451. Out:    none
  452. Xin:    none
  453. Xout:    none
  454. Return:    pointer to initialized communication information
  455. Notes:
  456. ***********************************************************/
  457. WTCOMM WtConnect(Widget toplevel, char *exepath)
  458. {
  459.     WTCOMM comm;        /* for return value */
  460.     XtInputId inputid;    /* input id for input callback */
  461.     int fd[4];            /* array of pipe file descriptors */
  462.     int i;
  463.  
  464.     if (!toplevel || !exepath || !*exepath) {
  465.         return((WTCOMM) 0);        /* bad values passed in */
  466.     }
  467.     /*
  468.      * Create the pipes.  They will be used as follows:
  469.      *        fd[0] - client read from tool
  470.      *        fd[1] - tool write to client
  471.      *        fd[2] - tool read from client
  472.      *        fd[3] - client write to tool
  473.      */
  474.     if (pipe(&fd[0])) {
  475.         return((WTCOMM) 0);        /* error */
  476.     }
  477.     if (pipe(&fd[2])) {
  478.         for (i = 0; i < 2; i++) {
  479.             close(i);
  480.         }
  481.         return((WTCOMM) 0);        /* error */
  482.     }
  483.     /* close client's file descriptors on exec of tool */
  484.     if ((fcntl(fd[0], F_SETFD, 1) == -1) || (fcntl(fd[3], F_SETFD, 1) == -1)) {
  485.         for (i = 0; i < 4; i++) {
  486.             close(i);
  487.         }
  488.         return((WTCOMM) 0);        /* error */
  489.     }
  490.     oldsigfunc = signal(SIGPIPE, SIG_IGN);    /* don't die on SIGPIPE signals */
  491.     /*
  492.      * Allocate and initialize the WT Client communication info struct.
  493.      */
  494.     comm = (WTCOMM) calloc(1, sizeof(WTCOMMDATA));
  495.     if (comm) {
  496.         comm->client = (char *) calloc(1, strlen("WTClient") + 1);
  497.         comm->tool = (char *) calloc(1, strlen(exepath) + 10);
  498.     }
  499.     if (!comm || !comm->client || !comm->tool) {
  500.         if (comm->client) free(comm->client);
  501.         if (comm->tool) free(comm->tool);
  502.         if (comm) free(comm);
  503.         for (i = 0; i < 4; i++) {
  504.             close(i);
  505.         }
  506.         return((WTCOMM) 0);    
  507.     }
  508.     strcpy(comm->client, "WTClient");
  509.     /*
  510.      * Build a unique tool id for this invocation of the tool consisting
  511.      * of the read and write file descriptors and the invocation path.
  512.      *   FORMAT:    readfd_writefd_path
  513.      *   EXAMPLE:    7_8_/tools/wtserver
  514.      */
  515.     sprintf(comm->tool, "%d_%d_", fd[2], fd[1]);
  516.     strcat(comm->tool, exepath);
  517.     comm->cl_pipe.read = fd[0];
  518.     comm->tl_pipe.write = fd[1];
  519.     comm->tl_pipe.read = fd[2];
  520.     comm->cl_pipe.write = fd[3];
  521.     /*
  522.      * Add an input callback to receive messages from the new pipe.
  523.      */
  524.     comm->inputid = XtAppAddInput(XtWidgetToApplicationContext(toplevel),
  525.                 comm->cl_pipe.read, (XtPointer) XtInputReadMask,
  526.                 (XtInputCallbackProc) WtClMsgReceived, (XtPointer) comm);
  527.     comm->toplevel = toplevel;    /* remember toplevel shell */
  528.     comm->window = 0;            /* window id of tool set later */
  529.     return(comm);
  530. } /* WtConnect */
  531.  
  532. /*COMMENT***************************************************
  533. ;WtDisconnect
  534. Title:    Shut down WT Client communication
  535. In:        comm - pointer to communication information
  536. Out:    none
  537. Xin:    none
  538. Xout:    none
  539. Return:    none
  540. Notes:    Remove input callback, close file descriptors, free memory
  541. ***********************************************************/
  542. void WtDisconnect(WTCOMM comm)
  543. {
  544.     if (comm) {
  545.         if (comm->client) {
  546.             free(comm->client);
  547.             comm->client = 0;
  548.         }
  549.         if (comm->tool) {
  550.             free(comm->tool);
  551.             comm->tool = 0;
  552.         }
  553.         /*
  554.          * Remove the input callback (before closing file descriptors).
  555.          */
  556.         if (comm->inputid) {
  557.             XtRemoveInput(comm->inputid);
  558.             comm->inputid = 0;
  559.         }
  560.         /* 
  561.          * Close client's read/write file descriptors.
  562.          */
  563.         if (comm->cl_pipe.read != -1) {
  564.             close(comm->cl_pipe.read);
  565.             comm->cl_pipe.read = -1;
  566.         } 
  567.         if (comm->cl_pipe.write != -1) {
  568.             close(comm->cl_pipe.write);
  569.             comm->cl_pipe.write = -1;
  570.         } 
  571.         free(comm);
  572.         comm = 0;
  573.     }
  574.     if (oldsigfunc) {
  575.         signal(SIGPIPE, oldsigfunc);    /* restore prev func */
  576.         oldsigfunc = 0;
  577.     }
  578. } /* WtDisconnect */
  579.  
  580. /*COMMENT***************************************************
  581. ;WtClMsgReceived
  582. Title:    Process a message received from the Writing Tool.
  583. In:        cldata = WTAPI communication info
  584.         source = pointer to file descriptor that generated the event
  585.         id = ID that was returned from call to XtAppAddInput()
  586. Out:    none
  587. Xin:    none
  588. Xout:    none
  589. Return:    none
  590. Notes:    This function should be attached as an XtInputCallbackProc
  591.         on the client's read file descriptor.
  592. ***********************************************************/
  593. static void WtClMsgReceived(XtPointer cldata, int *source, XtInputId *id)
  594. {
  595.     WTCOMM comm = (WTCOMM) cldata;
  596.     MSG_ERRS stat;        /* status of message receive */
  597.  
  598.     if (!comm || (comm->cl_pipe.read < 0)) {
  599.         return;
  600.     }
  601.     stat = ReceiveMsg(comm->cl_pipe, comm->client);
  602.     /*
  603.      * If this input callback was triggered and then ReceiveMsg() failed
  604.      * it means the pipe went down unexpectedly or there is some other
  605.      * problem with the pipe.  We need to disconnect from the pipe and
  606.      * quit the WT session.
  607.      */
  608.     if (stat != MSG_OK) {
  609.         XtRemoveInput(comm->inputid);
  610.         comm->inputid = 0;
  611.         quitTool("Pipe is down or faulty.  Dropping the Writing Tool session.");
  612.     }
  613. } /* WtClMsgReceived */
  614.  
  615. /*COMMENT*******************************************************
  616. ;wtClReceiveMsg
  617. Title:    Receive a raw WTAPI message on the Client side and extract parameters
  618.         necessary to invoke wtClReceive().
  619. In:        sender = name of sending process
  620.         msg = pointer to raw WTAPI message
  621. Out:    none
  622. Return:    status of message
  623. Notes:     This function is intended to be used in the msgHandlers table
  624.         used by wreceiveMsg() in libunix/wmsg.c for WTAPI_TOOL_COMMAND,
  625.         WTAPI_TOOL_QUERY, and REPLY messages.
  626. ***************************************************************/
  627. static WTSTATUS wtClReceiveMsg(char *sender, char *msg)
  628. {
  629.     WTMSGHEADER headerbuf;
  630.     WTMSGHEADERP header = &headerbuf;
  631.     WTSTATUS status = 0;
  632.     WTBUFP inmsg = 0, inbuf = 0, rtmsg = 0, rtbuf = 0, retdata = 0;
  633.     int inlen, rtlen;
  634.     WTCOMM comm;
  635.     WTCOMM wtGetCommID(char *);
  636.  
  637.     /*
  638.      * Copy data from message into header buffer.  We can't just use a
  639.      * pointer because the message data may not be word aligned and this
  640.      * causes a Bus Error when referencing members of the structure,
  641.      * e.g. header->inbufsize.
  642.      */
  643.     memcpy((char *)header, (char *)msg, sizeof(WTMSGHEADER));
  644.     /*
  645.      * We now use the sizes from the header to allocate space for the
  646.      * incoming message.  Again, we must do this to make sure we are
  647.      * word aligned to avoid Bus Errors when structure overlays are used
  648.      * to pull out the data.
  649.      */
  650.     inlen = header->inmsgsize + header->inbufsize;
  651.     inmsg = 0;
  652.     inmsg = (WTBUFP)calloc(1, inlen);
  653.     if (!inmsg) {
  654.         return WTS_NOMEMORY;
  655.     }
  656.     memcpy((char *)inmsg, (char *)msg + sizeof(WTMSGHEADER), inlen);
  657.  
  658.     if (header->inbufsize) {
  659.         inbuf = inmsg + header->inmsgsize;
  660.     } else {
  661.         inbuf = (WTBUFP) 0;
  662.     }
  663.     if (header->rtmsgid != WTC_NOMESSAGE) {
  664.         rtlen = sizeof(WTMSGHEADER) + header->rtmsgsize + header->rtbufsize;
  665.         retdata = 0;
  666.         retdata = (WTBUFP)calloc(1, rtlen);
  667.         if (!retdata) {
  668.             rtmsg = (WTBUFP) 0;
  669.             rtbuf = (WTBUFP) 0;
  670.         } else {
  671.             rtmsg = (WTBUFP) retdata + sizeof(WTMSGHEADER);
  672.             if (header->rtbufsize) {
  673.                 rtbuf = rtmsg + header->rtmsgsize;
  674.             } else {
  675.                 rtbuf = (WTBUFP) 0;
  676.             }
  677.         }
  678.     } else {
  679.         rtmsg = (WTBUFP) 0;
  680.         rtbuf = (WTBUFP) 0;
  681.     }
  682.     comm = commHandle;
  683.     if (comm) {
  684.         status = wtClReceive(comm, header->inmsgid, inmsg, inbuf,
  685.                                 rtmsg, rtbuf, &header->rtbufsize);
  686.     }
  687.     if (comm && (header->rtmsgid != WTC_NOMESSAGE)) {
  688.         header->inmsgid     = header->rtmsgid;
  689.         header->inmsgsize = header->rtmsgsize;
  690.         header->inbufsize = header->rtbufsize;
  691.         header->rtmsgid     = WTC_NOMESSAGE;
  692.         header->rtmsgsize = 0;
  693.         header->rtbufsize = 0;
  694.         memcpy((char *)retdata, (char *)header, sizeof(WTMSGHEADER));
  695.         SendMsg(comm->cl_pipe, comm->client, comm->tool, REPLY, retdata, rtlen);
  696.     }
  697.     if (inmsg) {
  698.         free((char *)inmsg);
  699.     }
  700.     if (retdata) {
  701.         free((char *)retdata);
  702.     }
  703.     return status;
  704. } /* wtClReceiveMsg */
  705. #endif /* WTAPI_CLIENT */
  706.  
  707. #ifdef WTAPI_SERVER
  708. /*COMMENT***************************************************
  709. ;WTInitComm
  710. Title:    Initialize WT Server communication
  711. In:        toplevel - toplevel widget of client
  712.         exepath - full path to executable
  713.         read_fd - read file descriptor
  714.         write_fd - write file descriptor
  715. Out:    none
  716. Xin:    none
  717. Xout:    none
  718. Return:    pointer to initialized communication information
  719. Notes:
  720. ***********************************************************/
  721. WTCOMM WTInitComm(Widget toplevel, char *exepath, int read_fd, int write_fd)
  722. {
  723.     WTCOMM comm;        /* for return value */
  724.     XtInputId inputid;    /* input id for input callback */
  725.     int i;
  726.  
  727.     if (!toplevel || !exepath || !*exepath) {
  728.         return((WTCOMM) 0);        /* bad values passed in */
  729.     }
  730.     oldsigfunc = signal(SIGPIPE, SIG_IGN);    /* don't die on SIGPIPE signals */
  731.     /*
  732.      * Allocate and initialize the WT Client communication info struct.
  733.      */
  734.     comm = (WTCOMM) calloc(1, sizeof(WTCOMMDATA));
  735.     if (comm) {
  736.         comm->client = (char *) calloc(1, strlen("WTClient") + 1);
  737.         comm->tool = (char *) calloc(1, strlen(exepath) + 10);
  738.     }
  739.     if (!comm || !comm->client || !comm->tool) {
  740.         if (comm->client) free(comm->client);
  741.         if (comm->tool) free(comm->tool);
  742.         if (comm) free(comm);
  743.         return((WTCOMM) 0);    
  744.     }
  745.     strcpy(comm->client, "WTClient");
  746.     /*
  747.      * Build a unique tool id for this invocation of the tool consisting
  748.      * of the read and write file descriptors and the invocation path.
  749.      *   FORMAT:    readfd_writefd_path
  750.      *   EXAMPLE:    7_8_/tools/wtserver
  751.      */
  752.     sprintf(comm->tool, "%d_%d_", read_fd, write_fd);
  753.     strcat(comm->tool, exepath);
  754.     comm->tl_pipe.read = read_fd;
  755.     comm->tl_pipe.write = write_fd;
  756.     comm->cl_pipe.read = -1;
  757.     comm->cl_pipe.write = -1;
  758.     /*
  759.      * Add an input callback to receive messages from the new pipe.
  760.      */
  761.     comm->inputid = XtAppAddInput(XtWidgetToApplicationContext(toplevel),
  762.                 comm->tl_pipe.read, (XtPointer) XtInputReadMask,
  763.                 (XtInputCallbackProc) WtTlMsgReceived, (XtPointer) comm);
  764.     comm->toplevel = toplevel;    /* remember toplevel shell */
  765.     comm->window = 0;            /* window id of client set later */
  766.     return(comm);
  767. } /* WTInitComm */
  768.  
  769. /*COMMENT***************************************************
  770. ;WTCloseComm
  771. Title:    Shut down WT Server communication
  772. In:        comm - pointer to communication information
  773. Out:    none
  774. Xin:    none
  775. Xout:    none
  776. Return:    none
  777. Notes:    Remove input callback, close file descriptors, free memory
  778. ***********************************************************/
  779. void WTCloseComm(WTCOMM comm)
  780. {
  781.     if (comm) {
  782.         if (comm->client) {
  783.             free(comm->client);
  784.             comm->client = 0;
  785.         }
  786.         if (comm->tool) {
  787.             free(comm->tool);
  788.             comm->tool = 0;
  789.         }
  790.         /*
  791.          * Remove the input callback (before closing file descriptors).
  792.          */
  793.         if (comm->inputid) {
  794.             XtRemoveInput(comm->inputid);
  795.             comm->inputid = 0;
  796.         }
  797.         /* 
  798.          * Close server's read/write file descriptors.
  799.          */
  800.         if (comm->tl_pipe.read != -1) {
  801.             close(comm->tl_pipe.read);
  802.             comm->tl_pipe.read = -1;
  803.         } 
  804.         if (comm->tl_pipe.write != -1) {
  805.             close(comm->tl_pipe.write);
  806.             comm->tl_pipe.write = -1;
  807.         } 
  808.         free(comm);
  809.         comm = 0;
  810.     }
  811.     if (oldsigfunc) {
  812.         signal(SIGPIPE, oldsigfunc);    /* restore prev func */
  813.         oldsigfunc = 0;
  814.     }
  815. } /* WTCloseComm */
  816.  
  817. /*COMMENT***************************************************
  818. ;WtTlMsgReceived
  819. Title:    Process a message received from the WT Client.
  820. In:        cldata = WTAPI communication info
  821.         source = pointer to file descriptor that generated the event
  822.         id = ID that was returned from call to XtAppAddInput()
  823. Out:    none
  824. Xin:    none
  825. Xout:    none
  826. Return:    none
  827. Notes:    This function should be attached as an XtInputCallbackProc
  828.         on the server's read file descriptor.
  829. ***********************************************************/
  830. static void WtTlMsgReceived(XtPointer cldata, int *source, XtInputId *id)
  831. {
  832.     WTCOMM comm = (WTCOMM) cldata;
  833.     MSG_ERRS stat;        /* status of message receive */
  834.  
  835.     if (!comm || (comm->tl_pipe.read < 0)) {
  836.         return;
  837.     }
  838.     stat = ReceiveMsg(comm->tl_pipe, comm->tool);
  839.     /*
  840.      * If this input callback was triggered and then ReceiveMsg() failed
  841.      * it means the pipe went down unexpectedly or there is some other
  842.      * problem with the pipe.  We need to disconnect from the pipe and
  843.      * quit the WT session.
  844.      */
  845.     if (stat != MSG_OK) {
  846.         XtRemoveInput(comm->inputid);
  847.         comm->inputid = 0;
  848.         quitTool("Pipe is down or faulty.  Aborting the Writing Tool session.");
  849.     }
  850. } /* WtTlMsgReceived */
  851.  
  852. /*COMMENT*******************************************************
  853. ;wtTlReceiveMsg
  854. Title:    Receive a raw WTAPI message on the Server side and extract parameters
  855.         necessary to invoke wtTlReceive().
  856. In:        sender = name of sending process
  857.         msg = pointer to raw WTAPI message
  858. Out:    none
  859. Return:    status of message
  860. Notes:     This function is intended to be used in the msgHandlers table
  861.         used by wreceiveMsg() in libunix/wmsg.c for WTAPI_TOOL_COMMAND,
  862.         WTAPI_TOOL_QUERY, and REPLY messages.
  863. ***************************************************************/
  864. static WTSTATUS wtTlReceiveMsg(char *sender, char *msg)
  865. {
  866.     WTMSGHEADER headerbuf;
  867.     WTMSGHEADERP header = &headerbuf;
  868.     WTSTATUS status = 0;
  869.     WTBUFP inmsg = 0, inbuf = 0, rtmsg = 0, rtbuf = 0, retdata = 0;
  870.     int inlen, rtlen;
  871.     WTCOMM comm;
  872.     WTCOMM wtGetCommID(char *);
  873.  
  874.     /*
  875.      * Copy data from message into header buffer.  We can't just use a
  876.      * pointer because the message data may not be word aligned and this
  877.      * causes a Bus Error when referencing members of the structure,
  878.      * e.g. header->inbufsize.
  879.      */
  880.     memcpy((char *)header, (char *)msg, sizeof(WTMSGHEADER));
  881.     /*
  882.      * We now use the sizes from the header to allocate space for the
  883.      * incoming message.  Again, we must do this to make sure we are
  884.      * word aligned to avoid Bus Errors when structure overlays are used
  885.      * to pull out the data.
  886.      */
  887.     inlen = header->inmsgsize + header->inbufsize;
  888.     inmsg = 0;
  889.     inmsg = (WTBUFP)calloc(1, inlen);
  890.     if (!inmsg) {
  891.         return WTS_NOMEMORY;
  892.     }
  893.     memcpy((char *)inmsg, (char *)msg + sizeof(WTMSGHEADER), inlen);
  894.  
  895.     if (header->inbufsize) {
  896.         inbuf = inmsg + header->inmsgsize;
  897.     } else {
  898.         inbuf = (WTBUFP) 0;
  899.     }
  900.     if (header->rtmsgid != WTC_NOMESSAGE) {
  901.         rtlen = sizeof(WTMSGHEADER) + header->rtmsgsize + header->rtbufsize;
  902.         retdata = 0;
  903.         retdata = (WTBUFP)calloc(1, rtlen);
  904.         if (!retdata) {
  905.             rtmsg = (WTBUFP) 0;
  906.             rtbuf = (WTBUFP) 0;
  907.         } else {
  908.             rtmsg = (WTBUFP) retdata + sizeof(WTMSGHEADER);
  909.             if (header->rtbufsize) {
  910.                 rtbuf = rtmsg + header->rtmsgsize;
  911.             } else {
  912.                 rtbuf = (WTBUFP) 0;
  913.             }
  914.         }
  915.     } else {
  916.         rtmsg = (WTBUFP) 0;
  917.         rtbuf = (WTBUFP) 0;
  918.     }
  919.     comm = comm_id;
  920.     if (comm) {
  921.         status = wtTlReceive(comm, header->inmsgid, inmsg, inbuf,
  922.                                 rtmsg, rtbuf, &header->rtbufsize);
  923.     }
  924.     if (comm && (header->rtmsgid != WTC_NOMESSAGE)) {
  925.         header->inmsgid     = header->rtmsgid;
  926.         header->inmsgsize = header->rtmsgsize;
  927.         header->inbufsize = header->rtbufsize;
  928.         header->rtmsgid     = WTC_NOMESSAGE;
  929.         header->rtmsgsize = 0;
  930.         header->rtbufsize = 0;
  931.         memcpy((char *)retdata, (char *)header, sizeof(WTMSGHEADER));
  932.         SendMsg(comm->tl_pipe, comm->tool, comm->tool, REPLY, retdata, rtlen);
  933.     }
  934.     if (inmsg) {
  935.         free((char *)inmsg);
  936.     }
  937.     if (retdata) {
  938.         free((char *)retdata);
  939.     }
  940.     return status;
  941. } /* wtTlReceiveMsg */
  942. #endif /* WTAPI_SERVER */
  943.