home *** CD-ROM | disk | FTP | other *** search
/ What PC? 1996 April / WHAT_PC_APR_96.ISO / internet / twinsock / src / twinsock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-23  |  12.0 KB  |  632 lines

  1. /*
  2.  *  TwinSock - "Troy's Windows Sockets"
  3.  *
  4.  *  Copyright (C) 1994  Troy Rollo <troy@cbme.unsw.EDU.AU>
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the license in the file LICENSE.TXT included
  8.  *  with the TwinSock distribution.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
  13.  */
  14.  
  15. #include <winsock.h>
  16. #include <stdlib.h>
  17. #include <ctype.h>
  18. #include "twinsock.h"
  19. #include "tx.h"
  20.  
  21. HINSTANCE    hinst;
  22.  
  23. extern    far pascal RegisterManager(HWND hwnd);
  24. extern    far pascal ResponseReceived(struct tx_request *ptxr);
  25. extern far pascal SetInitialised(void);
  26. static void SendInitRequest(void);
  27. void    Shutdown(void);
  28. void    OpenPort(void);
  29. extern    int    iPortChanged;
  30.  
  31. #define    READ_MAX    1024
  32. #define    TIMER_ID_SEND        1
  33. #define    TIMER_ID_RECEIVE    2
  34. #define    TIMER_ID_FLUSH        3
  35. #define    TIMER_ID_BREAK        4
  36. #define TIMER_ID_COMMCHECK    5
  37.  
  38. static    int    idComm;
  39. static    HWND    hwnd;
  40. static    BOOL    bFlushing = FALSE;
  41. static    BOOL    bTerminal = TRUE;
  42.  
  43. #define    SCREEN_COLUMNS    80
  44. #define    SCREEN_ROWS    25
  45. static    char    aachScreen[SCREEN_ROWS][SCREEN_COLUMNS];
  46. static    int    iScrollRow = 0;
  47. static    int    iRow = 0, iColumn = 0;
  48. static    int    cyRow, cxColumn;
  49. #define    ROW_INDEX(x)    ((x + iScrollRow) % SCREEN_ROWS)
  50.  
  51. static    char    const    achProtoInit[] = "@$TSStart$@";
  52.  
  53. extern    enum Encoding eLine;
  54. static    int    iInitChar = 0;
  55. long    nDiscarded = 0;
  56. long    nBytesRecvd = 0;
  57.  
  58. extern    void PacketReceiveData(void *pvData, int iLen);
  59.  
  60. void    SetTransmitTimeout(void)
  61. {
  62.     KillTimer(hwnd, TIMER_ID_SEND);
  63.     SetTimer(hwnd, TIMER_ID_SEND, 10000, 0);
  64. }
  65.  
  66. void    KillTransmitTimeout(void)
  67. {
  68.     KillTimer(hwnd, TIMER_ID_SEND);
  69. }
  70.  
  71. void    SetReceiveTimeout(void)
  72. {
  73.     KillTimer(hwnd, TIMER_ID_RECEIVE);
  74.     SetTimer(hwnd, TIMER_ID_RECEIVE, 1500, 0);
  75. }
  76.  
  77. void    KillReceiveTimeout(void)
  78. {
  79.     KillTimer(hwnd, TIMER_ID_RECEIVE);
  80. }
  81.  
  82. void    FlushInput(void)
  83. {
  84.     KillTimer(hwnd, TIMER_ID_FLUSH);
  85.     bFlushing = TRUE;
  86.     SetTimer(hwnd, TIMER_ID_FLUSH, 1500, 0);
  87. }
  88.  
  89. static    void
  90. SendToScreen(char c)
  91. {
  92.  
  93.     RECT    rcClient;
  94.     RECT    rcRedraw;
  95.  
  96.     if (c == '\r')
  97.     {
  98.         iColumn = 0;
  99.     }
  100.     else if (c == '\b')
  101.     {
  102.         if (iColumn > 0)
  103.             iColumn--;
  104.     }
  105.     else if (c == '\n')
  106.     {
  107.         if (iRow < SCREEN_ROWS - 1)
  108.         {
  109.             iRow++;
  110.         }
  111.         else
  112.         {
  113.             memset(aachScreen[iScrollRow], 0x20, sizeof(aachScreen[iScrollRow]));
  114.             iScrollRow++;
  115.             while (iScrollRow >= SCREEN_ROWS)
  116.                 iScrollRow -= SCREEN_ROWS;
  117.             GetClientRect(hwnd, &rcClient);
  118.             ScrollWindow(hwnd, 0, -cyRow, &rcClient, 0);
  119.             UpdateWindow(hwnd);
  120.         }
  121.     }
  122.     else if (c >= 0x20 && c <= 0x7e)
  123.     {
  124.         aachScreen[ROW_INDEX(iRow)][iColumn] = c;
  125.         rcRedraw.top = iRow * cyRow;
  126.         rcRedraw.left = iColumn * cxColumn;
  127.         rcRedraw.bottom = rcRedraw.top + cyRow;
  128.         rcRedraw.right = rcRedraw.left + cxColumn;
  129.         InvalidateRect(hwnd, &rcRedraw, TRUE);
  130.         if (iColumn < SCREEN_COLUMNS - 1)
  131.             iColumn++;
  132.     }
  133. }
  134.  
  135. static    void
  136. AddChar(char c)
  137. {
  138.     SendToScreen(c);
  139.     if (c == achProtoInit[iInitChar])
  140.     {
  141.         iInitChar++;
  142.         if (iInitChar == strlen(achProtoInit))
  143.         {
  144.             iInitChar = 0;
  145.             bTerminal = 0;
  146.             RegisterManager(hwnd);
  147.             InitProtocol();
  148.             SendInitRequest();
  149.         }
  150.     }
  151.     else if (iInitChar == 9 && isdigit(c))
  152.     {
  153.         eLine = (enum Encoding) (c - '0');
  154.     }
  155.     else if (iInitChar)
  156.     {
  157.         iInitChar = 0;
  158.         eLine = E_6Bit;
  159.     }
  160. }
  161.  
  162. static    void    DoReading(void)
  163. {
  164.     static    char    achBuffer[READ_MAX];
  165.     static    BOOL    bAlreadyHere = FALSE;
  166.     int    nRead;
  167.     COMSTAT    cs;
  168.     int    i;
  169.  
  170.     if (bAlreadyHere)
  171.         return;
  172.     bAlreadyHere = TRUE;
  173.     do
  174.     {
  175.         nRead = ReadComm(idComm, achBuffer, READ_MAX);
  176.         if (nRead <= 0)
  177.         {
  178.             GetCommError(idComm, &cs);
  179.             nRead = -nRead;
  180.         }
  181.         if (nRead)
  182.         {
  183.             if (bTerminal)
  184.             {
  185.                 HideCaret(hwnd);
  186.                 for (i = 0; i < nRead; i++)
  187.                     AddChar(achBuffer[i]);
  188.                 SetCaretPos(iColumn * cxColumn, iRow * cyRow);
  189.                 ShowCaret(hwnd);
  190.             }
  191.             else if (bFlushing)
  192.             {
  193.                 nDiscarded += nRead;
  194.                 FlushInput();
  195.             }
  196.             else
  197.             {
  198.                 nBytesRecvd += nRead;
  199.                 PacketReceiveData(achBuffer, nRead);
  200.             }
  201.         }
  202.     } while (nRead || cs.cbInQue);
  203.     bAlreadyHere = FALSE;
  204. }
  205.  
  206. int    SendData(void *pvData, int iDataLen)
  207. {
  208.     int    nWritten;
  209.     COMSTAT    cs;
  210.     int    iLen;
  211.  
  212.     if (bFlushing)
  213.         return iDataLen; /* Lie */
  214.     iLen = iDataLen;
  215.     do
  216.     {
  217.         nWritten = WriteComm(idComm, pvData, iLen);
  218.         if (nWritten < 0)
  219.         {
  220.             GetCommError(idComm, &cs);
  221.             nWritten = -nWritten;
  222.         }
  223.         iLen -= nWritten;
  224.         pvData = (char *) pvData + nWritten;
  225.     } while (iLen);
  226.     return iDataLen;
  227. }
  228.  
  229. void
  230. PaintScreen(    HWND    hWnd)
  231. {
  232.     int    i, iRow;
  233.     int    iCol;
  234.     TEXTMETRIC tm;
  235.     HFONT    hfontOld;
  236.     HFONT    hfontFixed;
  237.     PAINTSTRUCT ps;
  238.     int    cyHeight;
  239.     int    yPos;
  240.  
  241.     BeginPaint(hWnd, &ps);
  242.     hfontFixed = (HFONT) GetStockObject(SYSTEM_FIXED_FONT);
  243.     hfontOld = (HFONT) SelectObject(ps.hdc, (HGDIOBJ) hfontFixed);
  244.     GetTextMetrics(ps.hdc, &tm);
  245.     cyHeight = tm.tmHeight + tm.tmExternalLeading;
  246.     for (i = 0; i < SCREEN_ROWS; i++)
  247.     {
  248.         iRow = ROW_INDEX(i);
  249.         TextOut(ps.hdc, 0, i * cyRow, aachScreen[iRow], SCREEN_COLUMNS);
  250.     }
  251.     SelectObject(ps.hdc, (HGDIOBJ) hfontOld);
  252.     EndPaint(hWnd, &ps);
  253. }
  254.  
  255. LRESULT    CALLBACK _export
  256. WindowProc(    HWND    hWnd,
  257.         UINT    wMsg,
  258.         WPARAM    wParam,
  259.         LPARAM    lParam)
  260. {
  261.     char    c;
  262.  
  263.     switch(wMsg)
  264.     {
  265.     case WM_COMMAND:
  266.         switch(wParam)
  267.         {
  268.         case 100:
  269.             if (CommsEdit(hWnd))
  270.             {
  271.                 if (iPortChanged)
  272.                 {
  273.                     CloseComm(idComm);
  274.                     OpenPort();
  275.                 }
  276.                 else
  277.                 {
  278.                     InitComm(idComm);
  279.                 }
  280.             }
  281.             break;
  282.  
  283.         case 101:
  284.             if (bTerminal)
  285.             {
  286.                 bTerminal = 0;
  287.                 RegisterManager(hwnd);
  288.                 SendInitRequest();
  289.             }
  290.             break;
  291.  
  292.         case 102:
  293.             if (!bTerminal)
  294.             {
  295.                 Shutdown();
  296.                 SendData("\030\030\030\030\030", 5);
  297.             }
  298.             break;
  299.  
  300.         case 103:
  301.             PostQuitMessage(0);
  302.             break;
  303.  
  304.         case 104:
  305.             if (bTerminal)
  306.             {
  307.                 SetCommBreak(idComm);
  308.                 SetTimer(hwnd, TIMER_ID_BREAK, 1500, 0);
  309.             }
  310.             break;
  311.  
  312.         case 105:
  313.             if (bTerminal)
  314.                 DialNumber(hWnd);
  315.             break;
  316.  
  317.         case 106:
  318.             if (!bTerminal)
  319.                 ShowProtoInfo(hWnd);
  320.             break;
  321.  
  322.         case 201:
  323.             About(hWnd);
  324.             break;
  325.         }
  326.         break;
  327.  
  328.     case WM_COMMNOTIFY:
  329.         switch(LOWORD(lParam))
  330.         {
  331.         case CN_RECEIVE:
  332.             DoReading();
  333.             break;
  334.         }
  335.         break;
  336.  
  337.     case WM_CHAR:
  338.         if (bTerminal)
  339.         {
  340.             c = wParam;
  341.             SendData(&c, 1);
  342.         }
  343.         break;
  344.  
  345.     case WM_TIMER:
  346.         switch(wParam)
  347.         {
  348.         case TIMER_ID_SEND:
  349.             TimeoutReceived();
  350.             break;
  351.  
  352.         case TIMER_ID_RECEIVE:
  353.             KillTimer(hWnd, TIMER_ID_RECEIVE);
  354.             PacketReceiveData(0, 0);
  355.             break;
  356.  
  357.         case TIMER_ID_FLUSH:
  358.             KillTimer(hWnd, TIMER_ID_FLUSH);
  359.             bFlushing = FALSE;
  360.             break;
  361.  
  362.         case TIMER_ID_BREAK:
  363.             ClearCommBreak(idComm);
  364.             KillTimer(hWnd, TIMER_ID_BREAK);
  365.             break;
  366.  
  367.          case TIMER_ID_COMMCHECK:
  368.              DoReading();
  369.              break;
  370.         }
  371.         break;
  372.  
  373.     case WM_PAINT:
  374.         PaintScreen(hWnd);
  375.         return 0;
  376.         break;
  377.  
  378.     case WM_SETFOCUS:
  379.         CreateCaret(hWnd, 0, cxColumn, cyRow);
  380.         SetCaretPos(iColumn * cxColumn, iRow * cyRow);
  381.         ShowCaret(hWnd);
  382.         break;
  383.  
  384.     case WM_KILLFOCUS:
  385.         DestroyCaret();
  386.         break;
  387.  
  388.     case WM_USER:
  389.         PacketTransmitData((void *) lParam, wParam, 0);
  390.         DoReading();
  391.         break;
  392.  
  393.     case WM_CLOSE:
  394.         PostQuitMessage(0);
  395.         break;
  396.     }
  397.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  398. }
  399.  
  400. void
  401. DataReceived(void *pvData, int iLen)
  402. {
  403.     static    struct tx_request *ptxr = 0;
  404.     static    struct tx_request txrHeader;
  405.     static    int    nBytes = 0;
  406.     short    nPktLen;
  407.     enum Functions ft;
  408.     int    nCopy;
  409.     int    i;
  410.  
  411.     while (iLen)
  412.     {
  413.         if (nBytes < 10)
  414.         {
  415.             nCopy = 10 - nBytes;
  416.             if (nCopy > iLen)
  417.                 nCopy = iLen;
  418.             memcpy((char *) &txrHeader + nBytes, pvData, nCopy);
  419.             nBytes += nCopy;
  420.             pvData = (char *) pvData + nCopy;
  421.             iLen -= nCopy;
  422.             if (nBytes == 10)
  423.             {
  424.                 nPktLen = ntohs(txrHeader.nLen);
  425.                 ptxr = (struct tx_request *) malloc(sizeof(struct tx_request) + nPktLen - 1);
  426.                 memcpy(ptxr, &txrHeader, 10);
  427.             }
  428.         }
  429.         if (nBytes >= 10)
  430.         {
  431.             nPktLen = ntohs(txrHeader.nLen);
  432.             ft = (enum Functions) ntohs(txrHeader.iType);
  433.             nCopy = nPktLen - nBytes;
  434.             if (nCopy > iLen)
  435.                 nCopy = iLen;
  436.             if (nCopy)
  437.             {
  438.                 memcpy((char *) ptxr + nBytes, pvData, nCopy);
  439.                 nBytes += nCopy;
  440.                 pvData = (char *) pvData + nCopy;
  441.                 iLen -= nCopy;
  442.             }
  443.             if (nBytes == nPktLen)
  444.             {
  445.                 if (ft == FN_Init)
  446.                 {
  447.                     if (ptxr->id == -1)
  448.                     {
  449.                         SetWindowText(hwnd, "TwinSock - Connected");
  450.                         CloseWindow(hwnd);
  451.                         SetInitialised();
  452.                     }
  453.                 }
  454.                 else if (ft == FN_Message)
  455.                 {
  456.                     SendToScreen('\r');
  457.                     SendToScreen('\n');
  458.                     for (i = 0; i < nPktLen - 10; i++)
  459.                         SendToScreen(ptxr->pchData[i]);
  460.                 }
  461.                 else
  462.                 {
  463.                     ResponseReceived(ptxr);
  464.                 }
  465.                 free(ptxr);
  466.                 ptxr = 0;
  467.                 nBytes = 0;
  468.             }
  469.         }
  470.     }
  471. }
  472.  
  473. static void
  474. SendInitRequest(void)
  475. {
  476.     struct    tx_request txr;
  477.  
  478.     txr.iType = htons(FN_Init);
  479.     txr.nArgs = 0;
  480.     txr.nLen = htons(10);
  481.     txr.id = -1;
  482.     txr.nError = 0;
  483.     PacketTransmitData(&txr, 10, 0);
  484. }
  485.  
  486. void
  487. Shutdown(void)
  488. {
  489.     bTerminal = 1;
  490.     SetWindowText(hwnd, "TwinSock - No Connection");
  491.     KillTimer(hwnd, TIMER_ID_SEND);
  492.     KillTimer(hwnd, TIMER_ID_RECEIVE);
  493.     KillTimer(hwnd, TIMER_ID_FLUSH);
  494.     ReInitPackets();
  495. }
  496.  
  497. void
  498. OpenPort(void)
  499. {
  500.     char    achProfileEntry[256];
  501.     char    achMsgBuf[512];
  502.     char    *pchError;
  503.  
  504.     do
  505.     {
  506.         iPortChanged = 0;
  507.         GetPrivateProfileString("Config", "Port", "COM1", achProfileEntry, 256, "TWINSOCK.INI");
  508.         idComm = OpenComm(achProfileEntry, 16384, 16384);
  509.         if (idComm < 0)
  510.         {
  511.         switch(idComm)
  512.         {
  513.             case IE_BADID:
  514.                 pchError = "No such device";
  515.                 break;
  516.  
  517.             case IE_BAUDRATE:
  518.                 pchError = "Speed not supported";
  519.                 break;
  520.  
  521.             case IE_BYTESIZE:
  522.                 pchError = "Byte size not supported";
  523.                 break;
  524.  
  525.             case IE_DEFAULT:
  526.                 pchError = "Bad default parameters for port";
  527.                 break;
  528.  
  529.             case IE_HARDWARE:
  530.                 pchError = "Port in use";
  531.                 break;
  532.  
  533.             case IE_MEMORY:
  534.                 pchError = "Out of memory";
  535.                 break;
  536.  
  537.             case IE_NOPEN:
  538.                 pchError = "Device not open";
  539.                 break;
  540.  
  541.             case IE_OPEN:
  542.                 pchError = "Device is already open";
  543.                 break;
  544.  
  545.             default:
  546.                 pchError = "Error Unknown";
  547.                 break;
  548.             }
  549.             sprintf(achMsgBuf,
  550.                 "Unable to open port \"%s\": %s",
  551.                 achProfileEntry,
  552.                 pchError);        
  553.             if (MessageBox(0, achMsgBuf, "TwinSock", MB_OKCANCEL) == IDCANCEL)
  554.                 exit(1);
  555.             if (!CommsEdit(hwnd))
  556.                 exit(1);
  557.         }
  558.     } while (idComm < 0);
  559.  
  560.     InitComm(idComm);
  561.     EnableCommNotification(idComm, hwnd, 1, 0);
  562.      SetTimer(hwnd, TIMER_ID_COMMCHECK, 1000, 0);
  563. }
  564.  
  565. #pragma argsused
  566. int    far    pascal
  567. WinMain(HINSTANCE    hInstance,
  568.     HINSTANCE    hPrec,
  569.     LPSTR        lpCmdLine,
  570.     int        nShow)
  571. {
  572.     WNDCLASS wc;
  573.     MSG    msg;
  574.     char    *pchError;
  575.     TEXTMETRIC    tm;
  576.     HDC    hdc;
  577.     HWND    hwndDesktop;
  578.     HFONT    hfontOld;
  579.     HFONT    hfontFixed;
  580.  
  581.     hinst = hInstance;
  582.     hwndDesktop = GetDesktopWindow();
  583.     hdc = GetDC(hwndDesktop);
  584.     hfontFixed = (HFONT) GetStockObject(SYSTEM_FIXED_FONT);
  585.     hfontOld = (HFONT) SelectObject(hdc, (HGDIOBJ) hfontFixed);
  586.     GetTextMetrics(hdc, &tm);
  587.     SelectObject(hdc, (HGDIOBJ) hfontOld);
  588.     ReleaseDC(hwnd, hdc);
  589.     cxColumn = tm.tmAveCharWidth;
  590.     cyRow = tm.tmHeight + tm.tmExternalLeading;
  591.  
  592.     memset(aachScreen, 0x20, sizeof(aachScreen));
  593.     wc.style = 0;
  594.     wc.lpfnWndProc = WindowProc;
  595.     wc.cbClsExtra = 0;
  596.     wc.cbWndExtra = 0;
  597.     wc.hInstance = hInstance;
  598.     wc.hIcon = LoadIcon(hInstance, "TSICON");
  599.     wc.hCursor = 0;
  600.     wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  601.     wc.lpszMenuName = "TS_MENU";
  602.     wc.lpszClassName = "TwinSock Communications";
  603.     RegisterClass(&wc);
  604.     hwnd = CreateWindow(    "TwinSock Communications",
  605.                 "TwinSock - No Connection",
  606.                 WS_OVERLAPPED |
  607.                  WS_CAPTION |
  608.                  WS_SYSMENU |
  609.                  WS_MINIMIZEBOX |
  610.                  WS_VISIBLE,
  611.                 CW_USEDEFAULT,
  612.                 CW_USEDEFAULT,
  613.                 cxColumn * SCREEN_COLUMNS + 2,
  614.                 cyRow * SCREEN_ROWS + 4 +
  615.                   GetSystemMetrics(SM_CYCAPTION) +
  616.                   GetSystemMetrics(SM_CYMENU),
  617.                 0,
  618.                 0,
  619.                 hInstance,
  620.                 0);
  621.  
  622.     OpenPort();
  623.  
  624.      while (GetMessage(&msg, 0, 0, 0))
  625.     {
  626.         {
  627.             TranslateMessage(&msg);
  628.             DispatchMessage(&msg);
  629.         }
  630.     }
  631. }
  632.