home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / telex1.sit / Telexƒ / Listen.c < prev    next >
C/C++ Source or Header  |  1991-05-04  |  7KB  |  218 lines

  1.                             /* ====================================== *\
  2.                             ** ==         AppleTalk  Teletype      == **
  3.                             ** ==            Listener code         == **
  4.                             ** ==               (INIT)             == **
  5.               ** == Copyright ⌐ Gamma Software, 1990 == **
  6.                             \* ====================================== */
  7.  
  8. /*
  9.  The AppleTalk cycle:
  10.  
  11. .. -> GetRequest(mySocket)
  12.             |
  13.             | ioCompletion
  14.             V
  15.       ReqCompleted -> InsertMessage -> SendResponse(mySocket)
  16.                                           |
  17.                                           | ioCompletion
  18.                                           V
  19.                                        RespCompleted -> GetRequest(mySocket)
  20.  
  21.  The life cycle of one element:
  22.  
  23.  InsertMessage -> (look for not-busy element) ->
  24.                -> busy=TRUE -> NMInstall(theElem)
  25.                                   |
  26.                                   | ioCompletion
  27.                                   V
  28.                                NoteCompleted -> NMRemove(theElem) -> busy=FALSE
  29.  
  30.   The structure of Telex messages:
  31.   +----------------------------+-----------------------------+
  32.   | Telex text (Pascal string) | Sender Name (Pascal String) |
  33.   +----------------------------+-----------------------------+
  34.  
  35.  */
  36.  
  37.  
  38.  
  39.  
  40. #include "TelexDef"
  41.  
  42.   static        void  ReqCompleted(void);   /* AppleTalk cycle: Req  received */
  43.   static        void  RespCompleted(void);  /* AppleTalk cycle: Resp sent     */
  44.  
  45.   static        void  Check(int);           /* Check OS return codes          */
  46.  
  47.   static        void  StartReq(Storage*);   /* Initiating routine             */
  48.  
  49.   static        short InsertMessage(Storage*);/* Insert a telex into NM queue */
  50.   static pascal void  NoteCompleted(NoteBuf*);/* Telex is shown: remove it    */
  51.  
  52. #ifdef THINK_C
  53.    static void*   GetA0(void);
  54. #  define SaveD3()  asm{\
  55.                       MOVE.L D3,-(A7)\
  56.                     }
  57. #  define RestD3()  asm {\
  58.                       MOVE.L (A7)+,D3\
  59.                     }
  60. #else
  61.   static void*    GetA0 (void) = 0x2008;   /* MOVE.L A0,D0    */
  62.   static void     SaveD3(void) = 0x2F03;   /* MOVE.L D3,-(A7) */
  63.   static void     RestD3(void) = 0x261F;   /* MOVE.L (A7)+,D3 */
  64. #endif
  65.  
  66. /*
  67.  * Start of the "GetRequest"
  68.  * This routine MUST BE THE FIRST in the code resource if MPW is used:
  69.  * it is started from the INIT-code
  70.  * (Think adds its own starter code into the resource header)
  71.  */
  72. void main(Storage* theData) {
  73.   StartReq(theData);
  74. }
  75.  
  76. /*
  77.  * The routine starts the GetRequest call.
  78.  * It's called from the Init at startup time and after SendResponse call
  79.  * Requests are received into the buffer in the Storage structure
  80.  */
  81. void StartReq(Storage* theData) {
  82.     theData->ReqBlock.ATPioCompletion  = (ProcPtr) ReqCompleted;
  83.     theData->ReqBlock.ATPcsCode             = tATPGetRequest;
  84.     theData->ReqBlock.ATPatpSocket       = theData->ReqSocket;
  85.     theData->ReqBlock.ATPreqPointer       = theData->ReqBuff;
  86.     theData->ReqBlock.ATPreqLength        = sizeof(theData->ReqBuff);
  87.  
  88.     Check(PGetRequest(&theData->ReqBlock,TRUE)); /* start async GetRequest      */
  89. }
  90.  
  91. /*
  92.  * End of the "GetRequest" operation:
  93.  * insert message in "Notification" queue, start "Response"
  94.  */
  95. static void ReqCompleted() {
  96.   Storage* theData;
  97.   SaveD3();                                  /* some compilers don't save it  */
  98.   theData =  (Storage*)GetA0();              /* A0 = ATblock address = Storage*/
  99.     
  100.     if(theData->ReqBlock.ATPioResult == 0) {   /* we received a nice request    */
  101.     theData->ReqBlock.ATPioResult      = 2;  /* mark the recv block as "free" */
  102.         theData->RespWord=InsertMessage(theData);/* insert received telex into NM */
  103.  
  104.     /* now prepare data for the Response */
  105.     theData->BDSArray[0].buffSize = sizeof(theData->RespWord);
  106.       theData->BDSArray[0].buffPtr  = (Ptr) &theData->RespWord;
  107.  
  108.       theData->RespBlock.ATPioCompletion = (ProcPtr)RespCompleted;
  109.       theData->RespBlock.ATPatpSocket       = theData->ReqSocket;
  110.         theData->RespBlock.ATPcsCode         = tATPSdRsp;
  111.         theData->RespBlock.ATPatpFlags     = atpXOvalue;
  112.         theData->RespBlock.ATPaddrBlock    = theData->ReqBlock.ATPaddrBlock;
  113.         theData->RespBlock.ATPbdsPointer   = (Ptr) theData->BDSArray;
  114.         theData->RespBlock.ATPnumOfBuffs   = 1;
  115.         theData->RespBlock.ATPbdsSize         = 1;
  116.         theData->RespBlock.ATPtransID      = theData->ReqBlock.ATPtransID;
  117.  
  118.       Check(PSendResponse(&theData->RespBlock,TRUE)); /* start async Response   */
  119.  
  120.     } else {                                   /* GetRequest operation failed   */
  121.       StartReq(theData);                       /* -> restart the GetRequest     */
  122.     }
  123.  
  124.     RestD3();                                  /* since not all compilers do it */
  125. }
  126.  
  127. /*
  128.  * Completion of the "Response" operation:
  129.  * start next "GetRequest" operation
  130.  */
  131. static void RespCompleted() {
  132.   Storage* theData;                          /* A0 = addr of respBlock        */
  133.   SaveD3();                                  /* again, save D3 reg            */
  134.     theData = (Storage*)((char*)GetA0()-sizeof(ATPParamBlock));
  135.     
  136.     theData->RespBlock.ATPioResult = 2;        /* response block is free        */
  137.     StartReq(theData);                         /* start new GetRequest          */
  138.     RestD3();                                  /* again, restore D3 reg         */
  139. }
  140.  
  141.  
  142. /*
  143.  * Insert the telex message received into the "Notification" queue
  144.  */
  145. static short InsertMessage(Storage* theData) {
  146.   short i     =  Nnotes;
  147.     short error = -1;
  148.     
  149.     /* Look for "Free" element among NoteBlocks*/
  150.     while(--i>=0 && theData->NoteBlocks[i].busy);
  151.  
  152.     if(i>=0) {                                                             /* "free" element found          */
  153.       NoteBuf* theNote = &theData->NoteBlocks[i];
  154.       unchar*  theMess =  theNote->mess;
  155.         unchar*  theBody = (unchar*)theData->ReqBuff;
  156.         unchar*  theUser = theBody+ *theBody +1; /* address of the Sender name    */
  157.       int      shift = 1;
  158.         int      j     = 0;
  159.     
  160.       /* Copy Telex Header from the Storage into the Element */
  161.         while(shift<MaxMessSize-1 && j < *theData->MessHeader) {
  162.           theMess[shift++] = theData->MessHeader[++j];
  163.         }
  164.         theMess[shift++] = ' ';                 /* a space after the header       */
  165.  
  166.     /* Copy User Name from the message into the Element*/
  167.         j = 0;
  168.       if(theUser + *theUser < theBody+theData->ReqBlock.ATPreqLength) {
  169.           while(shift<MaxMessSize && j < *theUser) {
  170.             theMess[shift++] = theUser[++j];
  171.           }   
  172.         }
  173.  
  174.     /* Write the separator */
  175.         if(shift<MaxMessSize-2) {              /* if there is enough space, draw  */
  176.           theMess[shift++] = ':';              /* the separator:the semicolon sign*/
  177.           theMess[shift++] = 0x0D;             /* and the Return (New Line) sign  */
  178.     }
  179.  
  180.     /* Copy Telex body  from the Message buffer into the Element */
  181.     j=0;
  182.         while(shift<MaxMessSize && j<*theBody) {
  183.           theMess[shift++] = theBody[++j];
  184.         }
  185.  
  186.         *theMess = (unchar) (shift-1);        /* store the output string length   */
  187.  
  188.         theNote->busy     = TRUE;             /* Mark the Element as "busy" and   */
  189.       theNote->q.nmResp = (ProcPtr)NoteCompleted; /* insert it into the NM queue*/
  190.  
  191.         if(NMInstall((QElemPtr) &theNote->q) == 0) error = 0;
  192.     }
  193.     return(error);
  194. }
  195.  
  196. /*
  197.  * Completion of the "Notification" request:
  198.  * remove from the NM queue, mark "Free"
  199.  */
  200. static pascal void  NoteCompleted(NoteBuf* theNote) {
  201.   NMRemove((QElemPtr) &theNote->q);
  202.     theNote->busy = FALSE;
  203. }
  204.  
  205. /*
  206.  * Check OS return codes: if non-zero, Beep: we can't do anything else here
  207.  */
  208. static void Check(int retcode) {
  209.   if(retcode != 0) SysBeep(1);
  210. }
  211.  
  212.  
  213. #ifdef THINK_C
  214. static void*    GetA0 () {asm{
  215.   MOVE.L A0,D0
  216. }}
  217. #endif
  218.