home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / cknwin.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  49KB  |  1,768 lines

  1. char *cknwin = "Win32 GUI Support 8.0.029, 10 March 2004";
  2. /* C K N W I N   --  Kermit GUI Windows support for Win32 systems */
  3.  
  4. /*
  5.   Author: Jeffrey Altman (jaltman@secure-endpoints.com)
  6.             Secure Endpoints Inc., New York City
  7.  
  8.   Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New
  9.   York.
  10. */
  11.  
  12. #include <windows.h>
  13. #include <tapi.h>
  14. #include <commctrl.h>
  15. #include "ckcdeb.h"
  16. #include "ckcker.h"
  17. #include "ckcasc.h"
  18. #include "cknwin.h"
  19. #include "ckowin.h"
  20. #include "ckntap.h"
  21. #include "ckocon.h"
  22. #include "ckuusr.h"
  23. #include "ckokey.h"
  24. #include "ckokvb.h"
  25. #include "ckosyn.h"
  26. #include "richedit.h"
  27.  
  28. /* Global variable */
  29.  
  30. HINSTANCE   hInst = 0 ;
  31. extern HINSTANCE hInstance ;
  32. HWND        hwndGUI = NULL ;
  33. HWND        hwndConsole = NULL ;
  34.  
  35. extern HWND hwndDialer ;
  36. extern LONG KermitDialerID ;
  37. extern int  DeleteStartupFile;
  38. extern char cmdfil[];
  39.  
  40. #ifdef KUI
  41. #include "kui/ikcmd.h"
  42. #include "kui/ikui.h"
  43. extern struct _kui_init kui_init;
  44. #endif /* KUI */
  45.  
  46. /* Function prototypes */
  47.  
  48. #ifdef CK_WIN
  49. int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
  50. #endif
  51.  
  52. InitApplication(HINSTANCE);
  53. InitInstance(HINSTANCE, int);
  54. LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
  55.  
  56. /* Application entry point */
  57.  
  58. #ifdef COMMENT
  59. int WINAPI WinMain(hinstance, hPrevInstance, lpCmdLine, nCmdShow)
  60. HINSTANCE hinstance;
  61. HINSTANCE hPrevInstance;
  62. LPSTR lpCmdLine;
  63. int nCmdShow;
  64. #endif
  65.  
  66.  
  67. #ifndef CK_WIN
  68. HANDLE WindowThread = INVALID_HANDLE_VALUE;
  69. DWORD  WindowThreadId = -1 ;
  70.  
  71. void
  72. ckWindowThread( void * hInstance )
  73. {
  74.     HINSTANCE hinstance = (HINSTANCE) hInstance ;
  75.     int nCmdShow = SW_SHOW ;
  76.     MSG msg;
  77.     extern int SysInited;
  78.  
  79.     setint();
  80.  
  81.     if (!InitApplication(hinstance))
  82.     {
  83.         debug( F100, "ckWindowThread InitApplication failed","",0 );
  84.         WindowThreadId = 0;
  85.         _endthread();
  86.     }
  87.  
  88.     if (!InitInstance(hinstance, nCmdShow))
  89.     {
  90.         debug( F100, "ckWindowThread InitInstance failed","",0 );
  91.         WindowThreadId = 0;
  92.         _endthread();
  93.     }
  94.  
  95.     debug( F100, "ckWindowThread Init successful","",0 );
  96.     WindowThreadId = GetCurrentThreadId();
  97.  
  98.     while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
  99.         TranslateMessage(&msg);
  100.         DispatchMessage(&msg);
  101.     }
  102.  
  103. #ifndef NOKVERBS
  104.     if ( SysInited ) {
  105.         debug(F110,"ckWindowThread","dokverb QUIT",0);
  106.         dokverb( VTERM, K_QUIT );
  107.     }
  108.     else
  109. #endif /* NOKVERBS */
  110.         debug(F110,"ckWindowThread","quitting",0);
  111. }
  112.  
  113. int
  114. WindowThreadInit( void * hInstance )
  115. {
  116.     WindowThread = (HANDLE) _beginthread( ckWindowThread, 65535, hInstance ) ;
  117.     do {
  118.         msleep(50);
  119.     } while ( WindowThreadId == -1 );
  120.  
  121.     if ( WindowThreadId == 0 )
  122.         return FALSE;
  123.  
  124. #ifdef COMMENT
  125.     if (!AttachThreadInput( GetCurrentThreadId(), WindowThreadId, TRUE ))
  126.         printf("AttachThreadInput error = %d\n",GetLastError());
  127. #endif /* COMMENT */
  128.     return TRUE ;
  129. }
  130.  
  131. void
  132. WindowThreadClose( void )
  133. {
  134.     debug(F100,"Window Thread Close","",0);
  135.     PostMessage(hwndGUI, WM_QUIT, 0, 0);
  136.     msleep(50);
  137. }
  138. #else
  139. HANDLE MainThread = NULL ;
  140. #ifdef COMMENT
  141. int
  142. WindowThreadInit( void )
  143. {
  144.    return TRUE ;
  145. }
  146. #else /* COMMENT */
  147. HANDLE WindowThread = INVALID_HANDLE_VALUE;
  148. DWORD  WindowThreadId = -1 ;
  149.  
  150. void
  151. ckWindowThread( void * hInstance )
  152. {
  153.     HINSTANCE hinstance = (HINSTANCE) hInstance ;
  154.     int nCmdShow = SW_HIDE ;
  155.     MSG msg;
  156.  
  157.     WindowThreadId = GetCurrentThreadId();
  158.  
  159.     if (!InitApplication(hinstance))
  160.     {
  161.        debug( F100, "ckWindowThread InitApplication failed","",0 );
  162.        _endthread();
  163.     }
  164.  
  165.     if (!InitInstance(hinstance, nCmdShow))
  166.     {
  167.        debug( F100, "ckWindowThread InitInstance failed","",0 );
  168.        _endthread();
  169.     }
  170.  
  171.     debug( F100, "ckWindowThread Init successful","",0 );
  172.  
  173.     while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
  174.         TranslateMessage(&msg);
  175.         DispatchMessage(&msg);
  176.     }
  177. }
  178.  
  179. int
  180. WindowThreadInit( void * hInstance )
  181. {
  182.     WindowThread = (HANDLE) _beginthread( ckWindowThread, 65535, hInstance ) ;
  183.     while ( WindowThreadId == -1 )
  184.         msleep(50);
  185.     if (!AttachThreadInput( GetCurrentThreadId(), WindowThreadId, TRUE ))
  186.         printf("AttachThreadInput error = %d\n",GetLastError());
  187.     return TRUE ;
  188. }
  189. #endif /* COMMENT */
  190.  
  191. extern void Main( int, char ** ) ;
  192.  
  193. void
  194. ckMainThread( void * param )
  195. {
  196.     LPTSTR CmdLine = GetCommandLine() ;
  197.     HANDLE hOut, hIn ;
  198.     char ** argv;
  199.     int    argc = 0 ;
  200.     int i = 0, quote = 0 ;
  201.     char * p = CmdLine ;
  202.  
  203.     debug(F111,"GetCommandLine()",CmdLine,strlen(CmdLine));
  204.     hInstance = (HINSTANCE) param ;
  205.  
  206.     while( *p )
  207.     {
  208.        if ( *p == '"' && !quote ) {
  209.            quote++;
  210.        } else if ( quote && *p == '"' ) {
  211.            quote = 0;
  212.            while ( *(p+1) == ' ' )
  213.                p++ ;
  214.            if ( *(p+1) != '\0' )
  215.                argc++;
  216.        } else if ( !quote && *p == ' ' && *(p+1) != '\0' ) {
  217.            argc++ ;
  218.            while ( *(p+1) == ' ' )
  219.                p++ ;
  220.        }
  221.        p++;
  222.     }
  223.     argc++ ;
  224.     argv = malloc( (argc+1) * sizeof(char *) ) ;
  225.     debug(F111,"ckMainThread","argc",argc);
  226.     if ( argv == NULL ) {
  227.         fprintf(stderr,"Out of memory\n");
  228.         exit(1);
  229.     } else {
  230.         argv[argc] = "" ;
  231.  
  232.         p = CmdLine ;
  233.         for ( i = 0; i < argc ; i++ )
  234.         {
  235.             if ( *p == '"' ) {
  236.                 p++;
  237.                 argv[i] = p ;
  238.                 while (*p && (*p != '"'))
  239.                     p++;
  240.                 if (*p)
  241.                     *p++ = '\0';
  242.                 while (*p && (*p == ' '))
  243.                     p++;
  244.             } else {
  245.                 argv[i] = p ;
  246.                 while ( *p && (*p != ' ') )
  247.                     p++ ;
  248.                 if (*p)
  249.                     *p++ = '\0';
  250.                 while (*p && (*p == ' '))
  251.                     p++;
  252.             }
  253.             debug(F111,"ckMainThread argv",argv[i],i);
  254.         }
  255.     }
  256.  
  257. #ifndef KUI
  258.     if ( AllocConsole() )
  259.     {
  260.         hOut = CreateFile( "CONOUT$", GENERIC_READ | GENERIC_WRITE,
  261.                                   FILE_SHARE_READ | FILE_SHARE_WRITE,
  262.                                   NULL,
  263.                                   OPEN_EXISTING,
  264.                                   0,
  265.                                   0) ;
  266.         hIn = CreateFile( "CONIN$", GENERIC_READ | GENERIC_WRITE,
  267.                                   FILE_SHARE_READ | FILE_SHARE_WRITE,
  268.                                   NULL,
  269.                                   OPEN_EXISTING,
  270.                                   0,
  271.                                   0) ;
  272.  
  273.         SetStdHandle( STD_INPUT_HANDLE, hIn ) ;
  274.         SetStdHandle( STD_OUTPUT_HANDLE, hOut ) ;
  275.         SetStdHandle( STD_ERROR_HANDLE, hOut );
  276.     }
  277. #endif /* KUI */
  278.     Main( argc, argv ) ;
  279. }
  280.  
  281. HANDLE
  282. MainThreadInit( HINSTANCE hInst )
  283. {
  284.     MainThread = (HANDLE) _beginthread( ckMainThread, 65535, hInst ) ;
  285.     return(MainThread);
  286. }
  287.  
  288. int WINAPI
  289. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
  290. {
  291. #ifdef KUI
  292.     extern int deblog ;
  293.  
  294.     kui_init.nCmdShow = nCmdShow;
  295.     ckMainThread( hInstance ) ;
  296.     return 0;
  297. #else /* KUI */
  298.     MSG msg;
  299.     HINSTANCE hModule = GetModuleHandle(NULL);
  300.  
  301.     if (!InitApplication(hInstance))
  302.     {
  303.        debug( F100, "InitApplication failed","",0 );
  304.        return 0;
  305.     }
  306.  
  307.     if (!InitInstance(hInstance, nCmdShow))
  308.     {
  309.        debug( F100, "InitInstance failed","",0 );
  310.        return 0;
  311.     }
  312.  
  313.    MainThreadInit(hInstance) ;
  314.  
  315.     while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
  316.         printf("GetMessage\n");
  317.         TranslateMessage(&msg);
  318.         DispatchMessage(&msg);
  319.     }
  320.    return msg.wParam ;
  321. #endif /* KUI */
  322. }
  323. #endif
  324.  
  325. BOOL InitApplication(hinstance)
  326. HINSTANCE hinstance;
  327. {
  328.     WNDCLASSEX wcx;
  329.  
  330.     /*
  331.      * Fill in the window class structure with parameters
  332.      * that describe the main window.
  333.      */
  334.  
  335.     wcx.cbSize = sizeof(wcx);          /* size of structure      */
  336.     wcx.style = CS_HREDRAW |
  337.         CS_VREDRAW;                    /* redraw if size changes */
  338.     wcx.lpfnWndProc = MainWndProc;     /* points to window proc. */
  339.     wcx.cbClsExtra = 0;                /* no extra class memory  */
  340.     wcx.cbWndExtra = 0;                /* no extra window memory */
  341.     wcx.hInstance = hinstance;         /* handle of instance     */
  342.     wcx.hIcon = LoadIcon(NULL,
  343.         MAKEINTRESOURCE(1));           /* kermit 95 icon   */
  344.     wcx.hCursor = LoadCursor(NULL,
  345.         IDC_ARROW);                    /* predefined arrow       */
  346.     wcx.hbrBackground = GetStockObject(
  347.         WHITE_BRUSH);                  /* white background brush */
  348.     wcx.lpszMenuName =  "CkMainMenu";    /* name of menu resource  */
  349.     wcx.lpszClassName = "CkMainWClass";  /* name of window class   */
  350.     wcx.hIconSm = LoadImage(hinstance, /* small class icon       */
  351.         MAKEINTRESOURCE(5),
  352.                              IMAGE_ICON,
  353.  
  354.         GetSystemMetrics(SM_CXSMICON),
  355.         GetSystemMetrics(SM_CYSMICON),
  356.         LR_DEFAULTCOLOR);
  357.  
  358.     /* Register the window class. */
  359.  
  360.     return RegisterClassEx(&wcx);
  361. }
  362.  
  363. BOOL
  364. InitInstance(hinstance, nCmdShow)
  365. HINSTANCE hinstance;
  366. int nCmdShow;
  367. {
  368.     /* Save the application-instance handle. */
  369.  
  370.     hInst = hinstance;
  371.  
  372.     /* Create the main window. */
  373.  
  374. #ifndef CK_WIN
  375.    hwndGUI = CreateWindow(
  376.         "CkMainWClass",      /* name of window class        */
  377.         "Kermit 95",         /* title-bar string            */
  378.         WS_CHILD, /* top-level window            */
  379.         CW_USEDEFAULT,       /* default horizontal position */
  380.         CW_USEDEFAULT,       /* default vertical position   */
  381.         CW_USEDEFAULT,       /* default width               */
  382.         CW_USEDEFAULT,       /* default height              */
  383.         (HWND) hwndConsole,         /* console window             */
  384.         (HMENU) 1,        /* use class menu              */
  385.         hinstance,           /* handle of app. instance     */
  386.         (LPVOID) NULL);      /* no window-creation data     */
  387. #else
  388.    hwndGUI = CreateWindow(
  389.         "CkMainWClass",      /* name of window class        */
  390.         "Kermit 95",         /* title-bar string            */
  391.         WS_OVERLAPPEDWINDOW,
  392.         CW_USEDEFAULT,       /* default horizontal position */
  393.         CW_USEDEFAULT,       /* default vertical position   */
  394.         CW_USEDEFAULT,       /* default width               */
  395.         CW_USEDEFAULT,       /* default height              */
  396.         (HWND) NULL,
  397.         (HMENU) NULL,        /* use class menu              */
  398.         hinstance,           /* handle of app. instance     */
  399.         (LPVOID) NULL);      /* no window-creation data     */
  400. #endif
  401.  
  402.     if (!hwndGUI)
  403.         return FALSE;
  404.  
  405.    ShowWindow( hwndGUI, SW_HIDE ) ;
  406.    /* Let the dialer know */
  407.    if ( StartedFromDialer )
  408.       DialerSend( OPT_KERMIT_HWND, (LONG) hwndGUI ) ;
  409.  
  410.      /*
  411.       * Show the window and send a WM_PAINT message to the window
  412.       * procedure.
  413.       */
  414.  
  415.     ShowWindow(hwndGUI, nCmdShow);
  416.     UpdateWindow(hwndGUI);
  417.     return TRUE;
  418.  
  419. }
  420.  
  421. LRESULT CALLBACK
  422. MainWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
  423. {
  424.     LRESULT result = 0 ;
  425.     extern unsigned long startflags;
  426.  
  427.     switch ( msg ) {
  428.     case WM_QUERYENDSESSION:
  429.         debug(F111,"MainWndProc","WM_QUERYENDSESSION",msg);
  430.         result = TRUE;
  431.         if ( lparam & ENDSESSION_LOGOFF ) {
  432.             debug(F100,"ENDSESSION_LOGOFF","",0);
  433.             if ( startflags & 128 ) {
  434.                 debug(F100,"startflags & 128","",0);
  435.                 result = FALSE;
  436.             }
  437.         }
  438.         break;
  439.  
  440.     case WM_ENDSESSION:
  441.         debug(F111,"MainWndProc","WM_QUERYENDSESSION",msg);
  442.         if ( wparam && (lparam & ENDSESSION_LOGOFF) ) {
  443.             debug(F100,"ENDSESSION_LOGOFF","",0);
  444.             if ( startflags & 128 ) {
  445.                 debug(F100,"startflags & 128","",0);
  446.                 result = TRUE;
  447.             }
  448.         }
  449.         break;
  450.  
  451. #ifdef CK_TAPI
  452.     case OPT_TAPI_INIT:
  453.         debug(F110,"K95 WndProc","OPT_TAPI_INIT",0);
  454.         wintapiinit();
  455.         result = TRUE;
  456.         break;
  457.  
  458.     case OPT_TAPI_SHUTDOWN:
  459.         debug(F110,"K95 WndProc","OPT_TAPI_SHUTDOWN",0);
  460.         wintapishutdown();
  461.         result = TRUE;
  462.         break;
  463. #endif /* CK_TAPI */
  464.     case OPT_KERMIT_HANGUP:
  465.         debug(F110,"K95 WndProc","OPT_KERMIT_HANGUP",0);
  466. #ifndef NOLOCAL
  467.         if ( IsConnectMode() )
  468.             SetConnectMode( FALSE, CSX_USERDISC ) ;
  469. #endif /* NOLOCAL */
  470.         putkeystr( VCMD, "hangup\rexit\ryes\r" ) ;
  471.         DialerSend( OPT_KERMIT_HANGUP, 0 ) ;
  472.         result = TRUE;
  473.         break;
  474.  
  475. #ifndef NOLOCAL
  476.     case OPT_DIALER_EXIT:
  477.         debug(F110,"K95 WndProc","OPT_DIALER_EXIT",0);
  478.         StartedFromDialer = 0;
  479.         hwndDialer = 0;
  480.         KermitDialerID = 0;
  481.         result = TRUE;
  482.         break;
  483.  
  484.     case OPT_DIALER_HWND:
  485.         debug(F110,"K95 WndProc","OPT_DIALER_HWND",0);
  486.         StartedFromDialer = 1;
  487.         hwndDialer = (HWND)lparam;
  488.         KermitDialerID = wparam;
  489.         result = TRUE;
  490.         break;
  491.  
  492.     case OPT_DIALER_CONNECT: {
  493.         char buf[300], file[256];
  494.         debug(F110,"K95 WndProc","OPT_DIALER_CONNECT",0);
  495.         if ( GlobalGetAtomName((ATOM)lparam,file,sizeof(file)) ) {
  496.             debug(F110,"Take File",file,0);
  497.             ckmakmsg(buf,300,"take ",file,"\r",NULL);
  498.             GlobalDeleteAtom((ATOM)lparam);
  499.             putkeystr( VCMD, buf );
  500.             if ( IsConnectMode() )
  501.                 SetConnectMode(0,CSX_ESCAPE);
  502.  
  503.             if ( DeleteStartupFile ) {
  504.                 zdelet(cmdfil);
  505.                 ckstrncpy(cmdfil,file,CKMAXPATH+1);
  506.             } else {
  507.                 ckstrncpy(cmdfil,file,CKMAXPATH+1);
  508.                 DeleteStartupFile = 1;
  509.             }
  510.             DialerSend( OPT_KERMIT_HWND, (LONG) hwnd ) ;
  511.         }
  512.         result = TRUE;
  513.         break;
  514.     }
  515. #endif /* NOLOCAL */
  516.  
  517.     default:
  518.         debug(F111,"K95 WndProc","unknown message",msg);
  519.         debug(F111,"K95 WndProc","wparam",wparam);
  520.         debug(F111,"K95 WndProc","lparam",lparam);
  521.         result = DefWindowProc( hwnd, msg, wparam, lparam );
  522.    }
  523.    return result ;
  524. }
  525.  
  526. void
  527. StartDialer(void)
  528. {
  529.     extern int cmdlvl;
  530. #ifdef DCMDBUF
  531.     extern struct cmdptr *cmdstk;
  532. #else
  533.     extern struct cmdptr cmdstk[];
  534. #endif /* DCMDBUF */
  535.     extern char exedir[CKMAXPATH];
  536.     extern int nopush;
  537.     HWND   _hwndDialer = 0;
  538.     int    reuse;
  539.  
  540.     if ( nopush )
  541.         return;
  542.  
  543. #ifndef NOSPL
  544.     reuse = (cmdlvl == 0) && (ttchk() < 0);
  545. #else
  546.     reuse = (tlevel == -1) && (ttchk() < 0);
  547. #endif /* NOSPL */
  548.  
  549.     if ( StartedFromDialer ) {
  550.         if ( reuse ) {
  551.             DialerSend(OPT_KERMIT_HWND2, (unsigned long)hwndGUI);
  552.             DialerSend(OPT_KERMIT_PID,  GetCurrentProcessId());
  553.         }
  554.         ShowWindowAsync(hwndDialer,SW_SHOWNORMAL);
  555.         SetForegroundWindow(hwndDialer);
  556.     } else if (_hwndDialer = FindWindow(NULL, "Kermit-95 Dialer")) {
  557.         StartedFromDialer = 1;
  558.         hwndDialer = _hwndDialer;
  559.         KermitDialerID = 0;
  560.         DialerSend(OPT_KERMIT_HWND, (unsigned long)hwndGUI);
  561.         if ( reuse ) {
  562.             DialerSend(OPT_KERMIT_HWND2, (unsigned long)hwndGUI);
  563.             DialerSend(OPT_KERMIT_PID,  GetCurrentProcessId());
  564.         }
  565.         ShowWindowAsync(hwndDialer,SW_SHOWNORMAL);
  566.         SetForegroundWindow(hwndDialer);
  567.         StartedFromDialer = 0;
  568.     } else {
  569.         static char buf[512] = "start ", *p, *q;
  570.  
  571.         for ( p = exedir, q = buf + 6; *p; p++, q++ ) {
  572.             if ( *p == '/' ) {
  573.                 *q = '\\';
  574.             } else
  575.                 *q = *p;
  576.             if ( *q == '\\' ) {
  577.                 q++;
  578.                 *q = '\\';
  579.             }
  580.         }
  581.         for ( p = "k95dial.exe"; *p ; p++, q++ )
  582.             *q = *p;
  583.         if ( reuse ) {
  584.             for ( p = " -k "; *p ; p++, q++ )
  585.                 *q = *p;
  586.             for ( p = ckultoa((LONG) hwndGUI); *p ; p++, q++ )
  587.                 *q = *p;
  588.             *q++ = ' ';
  589.             for ( p = ckultoa((LONG) GetCurrentProcessId()); *p ; p++, q++ )
  590.                 *q = *p;
  591.         }
  592.         *q = '\0';
  593.         _zshcmd(buf,0);
  594.     }
  595. }
  596.  
  597. HWND
  598. GetConsoleHwnd( void )
  599. {
  600. #ifdef KUI
  601.     return getHwndKUI();
  602. #else /* KUI */
  603.     HWND hwndFound = NULL ;
  604.     char NewWindowTitle[1024] ;
  605.     char OldWindowTitle[1024] ;
  606.     int i = 0 ;
  607.  
  608.     GetConsoleTitle( OldWindowTitle, 1024 ) ;
  609.  
  610.     for ( i=0 ; i < 20 ; i++ )
  611.     {
  612.       wsprintf( NewWindowTitle, "%d/%d",
  613.                 GetTickCount(),
  614.                 GetCurrentProcessId());
  615.       SetConsoleTitle(NewWindowTitle);
  616.       Sleep(50);
  617.       hwndFound = FindWindow( NULL, NewWindowTitle ) ;
  618.       if ( hwndFound )
  619.          break;
  620.     }
  621.     debug(F111,"GetConsoleHwnd","Hwnd",hwndFound) ;
  622.     SetConsoleTitle( OldWindowTitle ) ;
  623.     return (hwndFound);
  624. #endif /* KUI */
  625. }
  626.  
  627. #ifdef KUI
  628. static LPWORD 
  629. lpwAlign( LPWORD lpIn )
  630. {
  631.     ULONG ul;
  632.  
  633.     ul = (ULONG) lpIn;
  634.     ul += 3;
  635.     ul >>=2;
  636.     ul <<=2;
  637.     return (LPWORD) ul;;
  638. }
  639.  
  640. static char * sid_buf = NULL;
  641. static int    sid_len = 0;
  642. static int    sid_timeout = 0;
  643. static UINT   sid_timer = 0;
  644.  
  645. #define ID_TEXT       150
  646. #define ID_SID_TEXT   200
  647. #define ID_SID_TIMER  (WM_USER+300)
  648.  
  649. static BOOL CALLBACK 
  650. SingleInputDialogProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  651. {
  652.     switch ( message ) {
  653.     case WM_INITDIALOG:
  654.         if ( sid_timeout ) {
  655.             sid_timer = SetTimer( hwndDlg, ID_SID_TIMER, sid_timeout * 1000, 
  656.                                   NULL);
  657.         }
  658.         if ( GetDlgCtrlID((HWND) wParam) != ID_SID_TEXT )
  659.         {
  660.             SetFocus(GetDlgItem( hwndDlg, ID_SID_TEXT));
  661.             return FALSE;
  662.         }
  663.         return TRUE;
  664.  
  665.     case WM_COMMAND:
  666.         switch ( LOWORD(wParam) ) {
  667.         case IDOK:
  668.             if ( !GetDlgItemText(hwndDlg, ID_SID_TEXT, sid_buf, sid_len) )
  669.                 *sid_buf = '\0';
  670.             /* fallthrough */
  671.         case IDCANCEL:
  672.             if ( sid_timeout )
  673.                 KillTimer(hwndDlg,sid_timer);
  674.             EndDialog(hwndDlg, LOWORD(wParam));
  675.             return TRUE;
  676.         }
  677.         break;
  678.     case WM_TIMER:
  679.         if ( sid_timeout )
  680.             KillTimer(hwndDlg,sid_timer);
  681.         EndDialog(hwndDlg, 0);
  682.         return TRUE;
  683.     }
  684.     return FALSE;
  685. }
  686.  
  687. /* 
  688.  * dialog widths are measured in 1/4 character widths
  689.  * dialog height are measured in 1/8 character heights
  690.  */
  691.  
  692. static LRESULT
  693. SingleInputDialog( HINSTANCE hinst, HWND hwndOwner, 
  694.                    char * ptext[], int numlines, int width, char * prompt, 
  695.                    int echo, char * dflt)
  696. {
  697.     HGLOBAL hgbl;
  698.     LPDLGTEMPLATE lpdt;
  699.     LPDLGITEMTEMPLATE lpdit;
  700.     LPWORD lpw;
  701.     LPWSTR lpwsz;
  702.     LRESULT ret;
  703.     int nchar, i;
  704.     char * p;
  705.  
  706.     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
  707.     if (!hgbl)
  708.         return -1;
  709.  
  710.     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
  711.  
  712.     // Define a dialog box.
  713.  
  714.     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
  715.                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
  716.                    | DS_SETFOREGROUND | DS_3DLOOK
  717.                    | DS_SHELLFONT | DS_NOFAILCREATE;
  718.     lpdt->cdit = numlines + 4;  // number of controls
  719.     lpdt->x  = 10;  
  720.     lpdt->y  = 10;
  721.     lpdt->cx = 20 + width * 4; 
  722.     lpdt->cy = 20 + (numlines + 4) * 14;
  723.  
  724.     lpw = (LPWORD) (lpdt + 1);
  725.     *lpw++ = 0;   // no menu
  726.     *lpw++ = 0;   // predefined dialog box class (by default)
  727.  
  728.     lpwsz = (LPWSTR) lpw;
  729.     nchar = MultiByteToWideChar (CP_ACP, 0, prompt, 
  730.                                     -1, lpwsz, 128);
  731.     lpw   += nchar;
  732.     *lpw++ = 8;                        // font size (points)
  733.     lpwsz = (LPWSTR) lpw;
  734.     nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 
  735.                                     -1, lpwsz, 128);
  736.     lpw   += nchar;
  737.  
  738.  
  739.     //-----------------------
  740.     // Define an OK button.
  741.     //-----------------------
  742.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  743.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  744.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
  745.     lpdit->dwExtendedStyle = 0;
  746.     lpdit->x  = (lpdt->cx - 14)/4 - 20; 
  747.     lpdit->y  = 10 + (numlines + 3) * 14;
  748.     lpdit->cx = 40; 
  749.     lpdit->cy = 14;
  750.     lpdit->id = IDOK;  // OK button identifier
  751.  
  752.     lpw = (LPWORD) (lpdit + 1);
  753.     *lpw++ = 0xFFFF;
  754.     *lpw++ = 0x0080;    // button class
  755.  
  756.     lpwsz = (LPWSTR) lpw;
  757.     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
  758.     lpw   += nchar;
  759.     *lpw++ = 0;           // no creation data
  760.  
  761.     //-----------------------
  762.     // Define an Cancel button.
  763.     //-----------------------
  764.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  765.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  766.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
  767.     lpdit->dwExtendedStyle = 0;
  768.     lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
  769.     lpdit->y  = 10 + (numlines + 3) * 14;
  770.     lpdit->cx = 40; 
  771.     lpdit->cy = 14;
  772.     lpdit->id = IDCANCEL;  // CANCEL button identifier
  773.  
  774.     lpw = (LPWORD) (lpdit + 1);
  775.     *lpw++ = 0xFFFF;
  776.     *lpw++ = 0x0080;    // button class
  777.  
  778.     lpwsz = (LPWSTR) lpw;
  779.     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
  780.     lpw   += nchar;
  781.     *lpw++ = 0;           // no creation data
  782.  
  783.     /* Add controls for preface data */
  784.     for ( i=0; i<numlines; i++) {
  785.         /*-----------------------
  786.          * Define a static text control.
  787.          *-----------------------*/
  788.         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  789.         lpdit = (LPDLGITEMTEMPLATE) lpw;
  790.         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
  791.         lpdit->dwExtendedStyle = 0;
  792.         lpdit->x  = 10; 
  793.         lpdit->y  = 10 + i * 14;
  794.         lpdit->cx = strlen(ptext[i]) * 4 + 10; 
  795.         lpdit->cy = 14;
  796.         lpdit->id = ID_TEXT + i;  // text identifier
  797.  
  798.         lpw = (LPWORD) (lpdit + 1);
  799.         *lpw++ = 0xFFFF;
  800.         *lpw++ = 0x0082;                         // static class
  801.  
  802.         lpwsz = (LPWSTR) lpw;
  803.         nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 
  804.                                          -1, lpwsz, 2*width);
  805.         lpw   += nchar;
  806.         *lpw++ = 0;           // no creation data
  807.     }
  808.     
  809.     /* Prompt */
  810.     /*-----------------------
  811.     * Define a static text control.
  812.     *-----------------------*/
  813.     lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  814.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  815.     lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
  816.     lpdit->dwExtendedStyle = 0;
  817.     lpdit->x  = 10; 
  818.     lpdit->y  = 10 + (numlines + 1) * 14;
  819.     lpdit->cx = strlen(prompt) * 4; 
  820.     lpdit->cy = 14;
  821.     lpdit->id = ID_TEXT + (numlines);  // text identifier
  822.  
  823.     lpw = (LPWORD) (lpdit + 1);
  824.     *lpw++ = 0xFFFF;
  825.     *lpw++ = 0x0082;                         // static class
  826.  
  827.     lpwsz = (LPWSTR) lpw;
  828.     nchar = MultiByteToWideChar (CP_ACP, 0, prompt, -1, lpwsz, 128);
  829.     lpw   += nchar;
  830.     *lpw++ = 0;           // no creation data
  831.  
  832.  
  833.     /*-----------------------
  834.     * Define an edit control.
  835.     *-----------------------*/
  836.     lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  837.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  838.     lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER
  839.         | (echo == 1 ? 0L : ES_PASSWORD);
  840.     lpdit->dwExtendedStyle = 0;
  841.     lpdit->x  = 10 + (strlen(prompt) + 1) * 4; 
  842.     lpdit->y  = 10 + (numlines + 1) * 14;
  843.     lpdit->cx = (width - (strlen(prompt) + 1)) * 4; 
  844.     lpdit->cy = 14;
  845.     lpdit->id = ID_SID_TEXT;                 // identifier
  846.  
  847.     lpw = (LPWORD) (lpdit + 1);
  848.     *lpw++ = 0xFFFF;
  849.     *lpw++ = 0x0081;                         // edit class
  850.  
  851.     lpwsz = (LPWSTR) lpw;
  852.     nchar = MultiByteToWideChar (CP_ACP, 0, dflt ? dflt : "", -1, lpwsz, 128);
  853.     lpw   += nchar;
  854.     *lpw++ = 0;           // no creation data
  855.  
  856.     GlobalUnlock(hgbl); 
  857.     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
  858.         hwndOwner, (DLGPROC) SingleInputDialogProc); 
  859.     GlobalFree(hgbl); 
  860.  
  861.     switch ( ret ) {
  862.     case 0:     /* Timeout */
  863.         return -1;
  864.     case IDOK:
  865.         return 1;
  866.     case IDCANCEL:
  867.         return 0;
  868.     default: {
  869.         char buf[256];
  870.         ckmakmsg(buf,256,"DialogBoxIndirect() failed ",ckitoa(GetLastError()), NULL, NULL);
  871.         MessageBox(hwndOwner,
  872.                     buf,
  873.                     "GetLastError()",
  874.                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  875.         return -1;
  876.     }
  877.     }
  878. }
  879.  
  880. int
  881. gui_txt_dialog(char * preface, char * prompt, int echo, 
  882.                char * buf, int buflen, char * dflt, int timeout)
  883. {
  884.     int maxwidth = 0;
  885.     int numlines = 0;
  886.     char * plines[16], *p = preface ? preface : "";
  887.     int i;
  888.  
  889.     if ( !buf || buflen <= 0 || buflen < (dflt ? strlen(dflt) : 0) )
  890.         return(-1);
  891.  
  892.     sid_buf = buf;
  893.     sid_len = buflen;
  894.     sid_timeout = timeout;
  895.  
  896.     for ( i=0; i<16; i++ ) 
  897.         plines[i] = NULL;
  898.  
  899.     while (*p && numlines < 16) {
  900.         plines[numlines++] = p;
  901.         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
  902.         if ( *p == '\r' && *(p+1) == '\n' ) {
  903.             *p++ = '\0';
  904.             p++;
  905.         } else if ( *p == '\n' ) {
  906.             *p++ = '\0';
  907.         } 
  908.         if ( strlen(plines[numlines-1]) > maxwidth )
  909.             maxwidth = strlen(plines[numlines-1]);
  910.     }
  911.  
  912.     i = strlen(prompt) + 1 + (buflen > 40 ? 40 : buflen);
  913.     if ( maxwidth < i )
  914.         maxwidth = i;
  915.  
  916.     return(SingleInputDialog(hInstance, hwndConsole, 
  917.                               plines, numlines, maxwidth, prompt, echo, dflt));
  918. }
  919.  
  920.  
  921. static int             mid_cnt = 0;
  922. static struct txtbox * mid_tb = NULL;
  923.  
  924. #define ID_MID_TEXT 300
  925.  
  926. static BOOL CALLBACK 
  927. MultiInputDialogProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  928. {
  929.     int i;
  930.  
  931.     switch ( message ) {
  932.     case WM_INITDIALOG:
  933.         if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
  934.         {
  935.             SetFocus(GetDlgItem( hwndDlg, ID_MID_TEXT));
  936.             return FALSE;
  937.         }
  938.         return TRUE;
  939.  
  940.     case WM_COMMAND:
  941.         switch ( LOWORD(wParam) ) {
  942.         case IDOK:
  943.             for ( i=0; i < mid_cnt ; i++ ) {
  944.                 if ( !GetDlgItemText(hwndDlg, ID_MID_TEXT+i, mid_tb[i].t_buf, mid_tb[i].t_len) )
  945.                     *mid_tb[i].t_buf = '\0';
  946.             }
  947.             /* fallthrough */
  948.         case IDCANCEL:
  949.             ShowWindowAsync(hwndConsole,SW_SHOWNORMAL);
  950.             SetForegroundWindow(hwndConsole);
  951.             EndDialog(hwndDlg, LOWORD(wParam));
  952.             return TRUE;
  953.         }
  954.     }
  955.     return FALSE;
  956. }
  957.  
  958. /* 
  959.  * dialog widths are measured in 1/4 character widths
  960.  * dialog height are measured in 1/8 character heights
  961.  */
  962.  
  963. static LRESULT
  964. MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, 
  965.                   char * ptext[], int numlines, int width, 
  966.                   int tb_cnt, struct txtbox * tb)
  967. {
  968.     HGLOBAL hgbl;
  969.     LPDLGTEMPLATE lpdt;
  970.     LPDLGITEMTEMPLATE lpdit;
  971.     LPWORD lpw;
  972.     LPWSTR lpwsz;
  973.     LRESULT ret;
  974.     int nchar, i, pwid;
  975.     char * p;
  976.  
  977.     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
  978.     if (!hgbl)
  979.         return -1;
  980.  
  981.     mid_cnt = tb_cnt;
  982.     mid_tb = tb;
  983.  
  984.     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
  985.  
  986.     // Define a dialog box.
  987.  
  988.     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
  989.                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
  990.                    | DS_SETFOREGROUND | DS_3DLOOK
  991.                    | DS_SHELLFONT | DS_NOFAILCREATE;
  992.     lpdt->cdit = numlines + (2 * tb_cnt) + 2;  // number of controls
  993.     lpdt->x  = 10;  
  994.     lpdt->y  = 10;
  995.     lpdt->cx = 20 + width * 4; 
  996.     lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
  997.  
  998.     lpw = (LPWORD) (lpdt + 1);
  999.     *lpw++ = 0;   // no menu
  1000.     *lpw++ = 0;   // predefined dialog box class (by default)
  1001.  
  1002.     lpwsz = (LPWSTR) lpw;
  1003.     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
  1004.     lpw   += nchar;
  1005.     *lpw++ = 8;                        // font size (points)
  1006.     lpwsz = (LPWSTR) lpw;
  1007.     nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 
  1008.                                     -1, lpwsz, 128);
  1009.     lpw   += nchar;
  1010.  
  1011.     //-----------------------
  1012.     // Define an OK button.
  1013.     //-----------------------
  1014.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  1015.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  1016.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
  1017.     lpdit->dwExtendedStyle = 0;
  1018.     lpdit->x  = (lpdt->cx - 14)/4 - 20; 
  1019.     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
  1020.     lpdit->cx = 40; 
  1021.     lpdit->cy = 14;
  1022.     lpdit->id = IDOK;  // OK button identifier
  1023.  
  1024.     lpw = (LPWORD) (lpdit + 1);
  1025.     *lpw++ = 0xFFFF;
  1026.     *lpw++ = 0x0080;    // button class
  1027.  
  1028.     lpwsz = (LPWSTR) lpw;
  1029.     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
  1030.     lpw   += nchar;
  1031.     *lpw++ = 0;           // no creation data
  1032.  
  1033.     //-----------------------
  1034.     // Define an Cancel button.
  1035.     //-----------------------
  1036.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  1037.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  1038.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
  1039.     lpdit->dwExtendedStyle = 0;
  1040.     lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
  1041.     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
  1042.     lpdit->cx = 40; 
  1043.     lpdit->cy = 14;
  1044.     lpdit->id = IDCANCEL;  // CANCEL button identifier
  1045.  
  1046.     lpw = (LPWORD) (lpdit + 1);
  1047.     *lpw++ = 0xFFFF;
  1048.     *lpw++ = 0x0080;    // button class
  1049.  
  1050.     lpwsz = (LPWSTR) lpw;
  1051.     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
  1052.     lpw   += nchar;
  1053.     *lpw++ = 0;           // no creation data
  1054.  
  1055.     /* Add controls for preface data */
  1056.     for ( i=0; i<numlines; i++) {
  1057.         /*-----------------------
  1058.          * Define a static text control.
  1059.          *-----------------------*/
  1060.         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  1061.         lpdit = (LPDLGITEMTEMPLATE) lpw;
  1062.         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
  1063.         lpdit->dwExtendedStyle = 0;
  1064.         lpdit->x  = 10; 
  1065.         lpdit->y  = 10 + i * 14;
  1066.         lpdit->cx = strlen(ptext[i]) * 4 + 10; 
  1067.         lpdit->cy = 14;
  1068.         lpdit->id = ID_TEXT + i;  // text identifier
  1069.  
  1070.         lpw = (LPWORD) (lpdit + 1);
  1071.         *lpw++ = 0xFFFF;
  1072.         *lpw++ = 0x0082;                         // static class
  1073.  
  1074.         lpwsz = (LPWSTR) lpw;
  1075.         nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 
  1076.                                          -1, lpwsz, 2*width);
  1077.         lpw   += nchar;
  1078.         *lpw++ = 0;           // no creation data
  1079.     }
  1080.     
  1081.     for ( i=0, pwid = 0; i<tb_cnt; i++) {
  1082.         if ( pwid < strlen(tb[i].t_lbl) )
  1083.             pwid = strlen(tb[i].t_lbl);
  1084.     }
  1085.  
  1086.     for ( i=0; i<tb_cnt; i++) {
  1087.         /* Prompt */
  1088.         /*-----------------------
  1089.          * Define a static text control.
  1090.          *-----------------------*/
  1091.         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  1092.         lpdit = (LPDLGITEMTEMPLATE) lpw;
  1093.         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
  1094.         lpdit->dwExtendedStyle = 0;
  1095.         lpdit->x  = 10; 
  1096.         lpdit->y  = 10 + (numlines + i + 1) * 14;
  1097.         lpdit->cx = pwid * 4; 
  1098.         lpdit->cy = 14;
  1099.         lpdit->id = ID_TEXT + numlines + i;  // text identifier
  1100.  
  1101.         lpw = (LPWORD) (lpdit + 1);
  1102.         *lpw++ = 0xFFFF;
  1103.         *lpw++ = 0x0082;                         // static class
  1104.  
  1105.         lpwsz = (LPWSTR) lpw;
  1106.         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].t_lbl ? tb[i].t_lbl : "", 
  1107.                                      -1, lpwsz, 128);
  1108.         lpw   += nchar;
  1109.         *lpw++ = 0;           // no creation data
  1110.  
  1111.         /*-----------------------
  1112.          * Define an edit control.
  1113.          *-----------------------*/
  1114.         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  1115.         lpdit = (LPDLGITEMTEMPLATE) lpw;
  1116.         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].t_echo == 1 ? 0L : ES_PASSWORD);
  1117.         lpdit->dwExtendedStyle = 0;
  1118.         lpdit->x  = 10 + (pwid + 1) * 4; 
  1119.         lpdit->y  = 10 + (numlines + i + 1) * 14;
  1120.         lpdit->cx = (width - (pwid + 1)) * 4; 
  1121.         lpdit->cy = 14;
  1122.         lpdit->id = ID_MID_TEXT + i;             // identifier
  1123.  
  1124.         lpw = (LPWORD) (lpdit + 1);
  1125.         *lpw++ = 0xFFFF;
  1126.         *lpw++ = 0x0081;                         // edit class
  1127.  
  1128.         lpwsz = (LPWSTR) lpw;
  1129.         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].t_dflt ? tb[i].t_dflt : "", 
  1130.                                      -1, lpwsz, 128);
  1131.         lpw   += nchar;
  1132.         *lpw++ = 0;           // no creation data
  1133.     }
  1134.  
  1135.     GlobalUnlock(hgbl); 
  1136.     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
  1137.         hwndOwner, (DLGPROC) MultiInputDialogProc); 
  1138.     GlobalFree(hgbl); 
  1139.  
  1140.     switch ( ret ) {
  1141.     case 0:     /* Timeout */
  1142.         return -1;
  1143.     case IDOK:
  1144.         return 1;
  1145.     case IDCANCEL:
  1146.         return 0;
  1147.     default: {
  1148.         char buf[256];
  1149.         ckmakmsg(buf,256,"DialogBoxIndirect() failed ",ckitoa(GetLastError()), NULL, NULL);
  1150.         MessageBox(hwndOwner,
  1151.                     buf,
  1152.                     "GetLastError()",
  1153.                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  1154.         return -1;
  1155.     }
  1156.     }
  1157. }
  1158.  
  1159. int
  1160. gui_mtxt_dialog(char * preface, int n, struct txtbox tb[])
  1161. {
  1162.     int maxwidth = 0;
  1163.     int numlines = 0;
  1164.     int len;
  1165.     char * plines[16], *p = preface ? preface : "";
  1166.     int i;
  1167.  
  1168.     for ( i=0; i<16; i++ ) 
  1169.         plines[i] = NULL;
  1170.  
  1171.     while (*p && numlines < 16) {
  1172.         plines[numlines++] = p;
  1173.         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
  1174.         if ( *p == '\r' && *(p+1) == '\n' ) {
  1175.             *p++ = '\0';
  1176.             p++;
  1177.         } else if ( *p == '\n' ) {
  1178.             *p++ = '\0';
  1179.         } 
  1180.         if ( strlen(plines[numlines-1]) > maxwidth )
  1181.             maxwidth = strlen(plines[numlines-1]);
  1182.     }
  1183.  
  1184.     for ( i=0;i<n;i++ ) {
  1185.         len = strlen(tb[i].t_lbl) + 1 + (tb[i].t_len > 40 ? 40 : tb[i].t_len);
  1186.         if ( maxwidth < len )
  1187.             maxwidth = len;
  1188.     }
  1189.  
  1190.     return(MultiInputDialog(hInstance, hwndConsole, 
  1191.                               plines, numlines, maxwidth, n, tb));
  1192. }
  1193.  
  1194.  
  1195. static BOOL CALLBACK 
  1196. VideoPopupDialogProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1197. {
  1198.     switch ( message ) {
  1199.     case WM_INITDIALOG:
  1200.         if ( sid_timeout ) {
  1201.             sid_timer = SetTimer( hwndDlg, ID_SID_TIMER, sid_timeout * 1000, 
  1202.                                   NULL);
  1203.         }
  1204.         return TRUE;
  1205.  
  1206.     case WM_COMMAND:
  1207.         switch ( LOWORD(wParam) ) {
  1208.         case IDOK:
  1209.         case IDCANCEL:
  1210.             if ( sid_timeout )
  1211.                 KillTimer(hwndDlg,sid_timer);
  1212.             EndDialog(hwndDlg, LOWORD(wParam));
  1213.             return TRUE;
  1214.         }
  1215.         break;
  1216.     case WM_TIMER:
  1217.         if ( sid_timeout )
  1218.             KillTimer(hwndDlg,sid_timer);
  1219.         EndDialog(hwndDlg, 0);
  1220.         return TRUE;
  1221.     }
  1222.     return FALSE;
  1223. }
  1224.  
  1225. /* 
  1226.  * dialog widths are measured in 1/4 character widths
  1227.  * dialog height are measured in 1/8 character heights
  1228.  */
  1229.  
  1230. static LRESULT
  1231. VideoPopupDialog( HINSTANCE hinst, HWND hwndOwner, videopopup * vp)
  1232. {
  1233.     HGLOBAL hgbl;
  1234.     LPDLGTEMPLATE lpdt;
  1235.     LPDLGITEMTEMPLATE lpdit;
  1236.     LPWORD lpw;
  1237.     LPWSTR lpwsz;
  1238.     LRESULT ret;
  1239.     int nchar, i, j;
  1240.     char * p;
  1241.  
  1242.     hgbl = GlobalAlloc(GMEM_ZEROINIT, 8192);
  1243.     if (!hgbl)
  1244.         return -1;
  1245.  
  1246.     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
  1247.  
  1248.     // Define a dialog box.
  1249.  
  1250.     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
  1251.                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
  1252.                    | DS_SETFOREGROUND | DS_3DLOOK
  1253.                    | DS_SETFONT | DS_NOFAILCREATE;
  1254.     lpdt->cdit = vp->height + 2;  // number of controls
  1255.     lpdt->x  = 10;  
  1256.     lpdt->y  = 10;
  1257.     lpdt->cx = 20 + vp->width * 4; 
  1258.     lpdt->cy = 20 + (vp->height + 1) * 8 + 14;
  1259.  
  1260.     lpw = (LPWORD) (lpdt + 1);
  1261.     *lpw++ = 0;   // no menu
  1262.     *lpw++ = 0;   // predefined dialog box class (by default)
  1263.  
  1264.     lpwsz = (LPWSTR) lpw;
  1265.     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
  1266.     lpw   += nchar;
  1267.     *lpw++ = 8;                        // font size (points)
  1268.     lpwsz = (LPWSTR) lpw;
  1269.     nchar = MultiByteToWideChar (CP_ACP, 0, "Lucida Console", -1, lpwsz, 128);
  1270.     lpw   += nchar;
  1271.  
  1272.  
  1273.     //-----------------------
  1274.     // Define an OK button.
  1275.     //-----------------------
  1276.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  1277.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  1278.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
  1279.     lpdit->dwExtendedStyle = 0;
  1280.     lpdit->x  = (lpdt->cx - 14)/4 - 20; 
  1281.     lpdit->y  = 10 + (vp->height + 1) * 8;
  1282.     lpdit->cx = 40; 
  1283.     lpdit->cy = 14;
  1284.     lpdit->id = IDOK;  // OK button identifier
  1285.  
  1286.     lpw = (LPWORD) (lpdit + 1);
  1287.     *lpw++ = 0xFFFF;
  1288.     *lpw++ = 0x0080;    // button class
  1289.  
  1290.     lpwsz = (LPWSTR) lpw;
  1291.     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
  1292.     lpw   += nchar;
  1293.     *lpw++ = 0;           // no creation data
  1294.  
  1295.     //-----------------------
  1296.     // Define an Cancel button.
  1297.     //-----------------------
  1298.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  1299.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  1300.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
  1301.     lpdit->dwExtendedStyle = 0;
  1302.     lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
  1303.     lpdit->y  = 10 + (vp->height + 1) * 8;
  1304.     lpdit->cx = 40; 
  1305.     lpdit->cy = 14;
  1306.     lpdit->id = IDCANCEL;  // CANCEL button identifier
  1307.  
  1308.     lpw = (LPWORD) (lpdit + 1);
  1309.     *lpw++ = 0xFFFF;
  1310.     *lpw++ = 0x0080;    // button class
  1311.  
  1312.     lpwsz = (LPWSTR) lpw;
  1313.     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
  1314.     lpw   += nchar;
  1315.     *lpw++ = 0;           // no creation data
  1316.  
  1317.     /* Add controls for preface data */
  1318.     for ( i=0; i<vp->height; i++) {
  1319.         /*-----------------------
  1320.          * Define a static text control.
  1321.          *-----------------------*/
  1322.         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  1323.         lpdit = (LPDLGITEMTEMPLATE) lpw;
  1324.         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
  1325.         lpdit->dwExtendedStyle = 0;
  1326.         lpdit->x  = 10; 
  1327.         lpdit->y  = 10 + i * 8;
  1328.         lpdit->cx = vp->width * 4 + 10; 
  1329.         lpdit->cy = 8;
  1330.         lpdit->id = ID_TEXT + i;  // text identifier
  1331.  
  1332.         lpw = (LPWORD) (lpdit + 1);
  1333.         *lpw++ = 0xFFFF;
  1334.         *lpw++ = 0x0082;                         // static class
  1335.  
  1336.         lpwsz = (LPWSTR) lpw;
  1337.         for ( j=0;j<vp->width && vp->c[i][j];j++ )
  1338.             *lpwsz++ = vp->c[i][j];
  1339.         *lpwsz++ = 0;
  1340.         lpw   = lpwsz;
  1341.  
  1342.         *lpw++ = 0;           // no creation data
  1343.     }
  1344.     
  1345.     GlobalUnlock(hgbl); 
  1346.     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
  1347.         hwndOwner, (DLGPROC) VideoPopupDialogProc); 
  1348.     GlobalFree(hgbl); 
  1349.  
  1350.     switch ( ret ) {
  1351.     case 0:     /* Timeout */
  1352.         return -1;
  1353.     case IDOK:
  1354.         return F_KVERB | K_HELP;
  1355.     case IDCANCEL:
  1356.         return 0;
  1357.     default: {
  1358.         char buf[256];
  1359.         ckmakmsg(buf,256,"DialogBoxIndirect() failed ",ckitoa(GetLastError()), NULL, NULL);
  1360.         MessageBox(hwndOwner,
  1361.                     buf,
  1362.                     "GetLastError()",
  1363.                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  1364.         return -1;
  1365.     }
  1366.     }
  1367. }
  1368.  
  1369. int
  1370. gui_videopopup_dialog(videopopup * vp, int timeout)
  1371. {
  1372.     int i;
  1373.  
  1374.     sid_timeout = timeout;
  1375.  
  1376.     return(VideoPopupDialog(hInstance, hwndConsole, vp));
  1377. }
  1378.  
  1379. int
  1380. gui_position(int x, int y)
  1381. {
  1382.     KuiSetTerminalPosition(x,y);
  1383.     msleep(50);
  1384.     return(1);
  1385. }
  1386.  
  1387. int
  1388. gui_resize_pixels(int x, int y)
  1389. {
  1390.     KuiSetTerminalSize(x,y);
  1391.     msleep(50);
  1392.     return(1);
  1393. }
  1394.  
  1395. int
  1396. gui_resize_mode(int x)
  1397. {
  1398.     KuiSetTerminalResizeMode(x);
  1399.     msleep(50);
  1400.     return(1);
  1401. }
  1402.  
  1403.  
  1404. int
  1405. gui_win_run_mode(int x)
  1406. {
  1407.     KuiSetTerminalRunMode(x);
  1408.     return(1);
  1409. }
  1410.  
  1411. int
  1412. gui_saveas_dialog(char * preface, char * prompt, int fc,
  1413.                   char * def, char * result, int rlength)
  1414. {
  1415.     return KuiDownloadDialog(prompt,def,result,rlength);
  1416. }
  1417.  
  1418. int 
  1419. get_gui_window_pos_x(void)
  1420. {
  1421.     RECT r;
  1422.  
  1423.     if ( GetWindowRect(getHwndKUI(), &r) ) {
  1424.         return r.left;
  1425.     } else 
  1426.         return 0;
  1427. }
  1428.  
  1429. int 
  1430. get_gui_window_pos_y(void)
  1431. {
  1432.     RECT r;
  1433.  
  1434.     if ( GetWindowRect(getHwndKUI(), &r) ) {
  1435.         return r.top;
  1436.     } else 
  1437.         return 0;
  1438. }
  1439.  
  1440. int 
  1441. get_gui_resize_mode(void)
  1442. {
  1443.     return KuiGetTerminalResizeMode();
  1444. }
  1445.  
  1446.  
  1447. static HWND hwndRichEdit = INVALID_HANDLE_VALUE;
  1448. static HWND hwndTextDlg  = INVALID_HANDLE_VALUE;
  1449. static HANDLE hRichEditLib = INVALID_HANDLE_VALUE;
  1450.  
  1451. static BOOL CALLBACK 
  1452. TextDialogProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1453. {
  1454.     switch ( message ) {
  1455.     case WM_INITDIALOG:
  1456.         if ( sid_timeout ) {
  1457.             sid_timer = SetTimer( hwndDlg, ID_SID_TIMER, sid_timeout * 1000, 
  1458.                                   NULL);
  1459.         }
  1460.  
  1461.         hwndTextDlg  = hwndDlg;
  1462.         hwndRichEdit = GetDlgItem( hwndDlg, ID_TEXT );
  1463.         PostRichEditInitSem();
  1464.         return TRUE;
  1465.  
  1466.     case WM_COMMAND:
  1467.         switch ( LOWORD(wParam) ) {
  1468.         case IDOK:
  1469.             if ( sid_timeout )
  1470.                 KillTimer(hwndDlg,sid_timer);
  1471.             hwndTextDlg = hwndRichEdit = INVALID_HANDLE_VALUE;
  1472.             EndDialog(hwndDlg, LOWORD(wParam));
  1473.             PostRichEditCloseSem();
  1474.             return TRUE;
  1475.         }
  1476.         break;
  1477.  
  1478.     case WM_CLOSE:
  1479.     case WM_TIMER:
  1480.         if ( sid_timeout )
  1481.             KillTimer(hwndDlg,sid_timer);
  1482.         hwndTextDlg = hwndRichEdit = INVALID_HANDLE_VALUE;
  1483.         EndDialog(hwndDlg, 0);
  1484.         PostRichEditCloseSem();
  1485.         return TRUE;
  1486.     }
  1487.     return FALSE;
  1488. }
  1489.  
  1490. /* 
  1491.  * dialog widths are measured in 1/4 character widths
  1492.  * dialog height are measured in 1/8 character heights
  1493.  */
  1494.  
  1495. static LRESULT
  1496. TextPopupDialog( HINSTANCE hinst, HWND hwndOwner, char * title, int h, int w)
  1497. {
  1498.     HGLOBAL hgbl;
  1499.     LPDLGTEMPLATE lpdt;
  1500.     LPDLGITEMTEMPLATE lpdit;
  1501.     LPWORD lpw;
  1502.     LPWSTR lpwsz;
  1503.     LRESULT ret;
  1504.     int nchar, i, j, font = 12;
  1505.     char * p;
  1506.  
  1507.     if ( !w ) w = 80;
  1508.     if ( !h ) h = 25;
  1509.  
  1510.     hgbl = GlobalAlloc(GMEM_ZEROINIT, 8192);
  1511.     if (!hgbl)
  1512.         return -1;
  1513.  
  1514.     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
  1515.  
  1516.     // Define a dialog box.
  1517.  
  1518.     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
  1519.                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
  1520.                    | DS_SETFOREGROUND | DS_3DLOOK
  1521.                    | DS_SETFONT | DS_NOFAILCREATE;
  1522.     lpdt->cdit = 2;  // number of controls
  1523.     lpdt->x  = 0;  
  1524.     lpdt->y  = 0;
  1525.     lpdt->cx = 14 + w * 4; 
  1526.     lpdt->cy = 32 + h * font;
  1527.  
  1528.     lpw = (LPWORD) (lpdt + 1);
  1529.     *lpw++ = 0;   // no menu
  1530.     *lpw++ = 0;   // predefined dialog box class (by default)
  1531.  
  1532.     lpwsz = (LPWSTR) lpw;   /* caption */
  1533.     nchar = MultiByteToWideChar (CP_ACP, 0, title, -1, lpwsz, 128);
  1534.     lpw   += nchar;
  1535.     *lpw++ = font;                        // font size (points)
  1536.     lpwsz = (LPWSTR) lpw;
  1537.     nchar = MultiByteToWideChar (CP_ACP, 0, "Lucida Console", -1, lpwsz, 128);
  1538.     lpw   += nchar;
  1539.  
  1540.  
  1541.     /*-----------------------
  1542.      * Define a Rich Edit 2.0 control.
  1543.      *-----------------------*/
  1544.     lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
  1545.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  1546.     lpdit->style = ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | 
  1547.                    ES_NUMBER | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP |
  1548.                    WS_VISIBLE;
  1549.     lpdit->dwExtendedStyle = 0; // WS_EX_CLIENTEDGE;
  1550.     lpdit->x  = 7; 
  1551.     lpdit->y  = 7;
  1552.     lpdit->cx = w * 4; 
  1553.     lpdit->cy = h * font;
  1554.     lpdit->id = ID_TEXT;
  1555.  
  1556.     lpw = (LPWORD) (lpdit + 1);
  1557.     lpwsz = (LPWSTR) lpw;
  1558.     nchar = MultiByteToWideChar (CP_ACP, 0, "RichEdit20W", -1, lpwsz, 50);
  1559.     lpw   += nchar;
  1560.  
  1561.     lpwsz = (LPWSTR) lpw;
  1562.     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 50);
  1563.     lpw   += nchar;
  1564.  
  1565.     *lpw++ = 0;           // no creation data
  1566.     
  1567.     //-----------------------
  1568.     // Define an OK button.
  1569.     //-----------------------
  1570.     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
  1571.     lpdit = (LPDLGITEMTEMPLATE) lpw;
  1572.     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
  1573.     lpdit->dwExtendedStyle = 0;
  1574.     lpdit->x  = 7 + w * 2 - 25; 
  1575.     lpdit->y  = 14 + h * font;
  1576.     lpdit->cx = 50; 
  1577.     lpdit->cy = 14;
  1578.     lpdit->id = IDOK;  // OK button identifier
  1579.  
  1580.     lpw = (LPWORD) (lpdit + 1);
  1581.     *lpw++ = 0xFFFF;
  1582.     *lpw++ = 0x0080;    // button class
  1583.  
  1584.     lpwsz = (LPWSTR) lpw;
  1585.     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
  1586.     lpw   += nchar;
  1587.     *lpw++ = 0;           // no creation data
  1588.  
  1589.     GlobalUnlock(hgbl); 
  1590.     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
  1591.                             hwndOwner, (DLGPROC) TextDialogProc); 
  1592.     GlobalFree(hgbl); 
  1593.  
  1594.     switch ( ret ) {
  1595.     case 0:     /* Timeout */
  1596.         return -1;
  1597.     case IDOK:
  1598.         return 1;
  1599.     default: {
  1600.         char buf[256];
  1601.         ckmakmsg(buf,256,"DialogBoxIndirect() failed ",ckitoa(GetLastError()), NULL, NULL);
  1602.         MessageBox(hwndOwner,
  1603.                     buf,
  1604.                     "GetLastError()",
  1605.                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  1606.         return -1;
  1607.     }
  1608.     }
  1609. }
  1610.  
  1611.  
  1612. static struct {
  1613.     char title[256];
  1614.     int  h;
  1615.     int  w;
  1616. } gui_text_params;
  1617.  
  1618. void 
  1619. gui_text_popup_thread(void * dummy)
  1620. {
  1621.     TextPopupDialog( hInstance, hwndConsole, 
  1622.                      gui_text_params.title, gui_text_params.h, gui_text_params.w );
  1623. }
  1624.  
  1625. static USHORT * EditStreamBuffer = NULL;
  1626. static int EditStreamMaxLen = 0;
  1627. static int EditStreamLen = 0;
  1628. static int stream_complete = 0;
  1629.  
  1630. static DWORD CALLBACK
  1631. EditStreamCallback(DWORD_PTR dwCookie,
  1632.                           LPBYTE pbBuff,
  1633.                           LONG cb,
  1634.                           LONG *pcb
  1635.                           )
  1636. {
  1637.   start:
  1638.     RequestRichEditMutex(INFINITE);
  1639.     if ( stream_complete && EditStreamLen == 0 ) {
  1640.         *pcb = 0;
  1641.     } else {
  1642.         if ( EditStreamLen == 0 ) {
  1643.             ReleaseRichEditMutex();
  1644.             Sleep(100);
  1645.             goto start;
  1646.         }
  1647.  
  1648.         if ( cb % 2 == 1 )
  1649.             cb--;
  1650.  
  1651.         if ( cb >= EditStreamLen * 2 ) {
  1652.             memcpy(pbBuff, EditStreamBuffer, EditStreamLen * 2);
  1653.             *pcb = EditStreamLen * 2;
  1654.             EditStreamLen = 0;
  1655.         } else {
  1656.             int i, j;
  1657.             memcpy(pbBuff, EditStreamBuffer, cb);
  1658.             *pcb = cb;
  1659.             for (i = 0, j = cb / 2; j <= EditStreamLen; i++, j++) {
  1660.                 EditStreamBuffer[i] = EditStreamBuffer[j];
  1661.             }
  1662.             EditStreamLen = i;
  1663.         }
  1664.     }
  1665.     ReleaseRichEditMutex();
  1666.     return 0;
  1667. }
  1668.  
  1669. static EDITSTREAM EditStream = { 0, 0, EditStreamCallback };
  1670.  
  1671. int
  1672. gui_text_popup_create(char * title, int h, int w)
  1673. {
  1674.     HANDLE thread;
  1675.  
  1676.     if ( hRichEditLib == INVALID_HANDLE_VALUE ) {
  1677.         hRichEditLib = LoadLibrary("riched20.dll");
  1678.         if ( hRichEditLib == INVALID_HANDLE_VALUE ) {
  1679.             MessageBox(hwndConsole,
  1680.                         "The library RICHED20.DLL required for GUI Text Edit controls is not present on this system",
  1681.                         "Error",
  1682.                         MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  1683.             return -1;
  1684.         }
  1685.     }
  1686.  
  1687.     CreateRichEditInitSem( FALSE );
  1688.     CreateRichEditCloseSem( FALSE );
  1689.     CreateRichEditMutex(FALSE);
  1690.     stream_complete = 0;
  1691.  
  1692.     gui_text_params.h = h;
  1693.     gui_text_params.w = w;
  1694.     ckstrncpy(gui_text_params.title,title,256);
  1695.  
  1696.     thread = (HANDLE) _beginthread( gui_text_popup_thread, 65535, NULL ) ;
  1697.     if ( thread != INVALID_HANDLE_VALUE )
  1698.         WaitRichEditInitSem( INFINITE );
  1699.     CloseRichEditInitSem();
  1700.  
  1701.     if ( hwndRichEdit != INVALID_HANDLE_VALUE ) {
  1702.         PostMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM) TRUE, (LPARAM) 0);
  1703.         PostMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT | SF_UNICODE, (LPARAM)&EditStream);
  1704.     }
  1705.     return 0;
  1706. }
  1707.  
  1708. int 
  1709. gui_text_popup_append(unsigned short uch)
  1710. {
  1711.   start:
  1712.     RequestRichEditMutex(INFINITE);
  1713.     if ( EditStreamMaxLen == 0 ) {
  1714.         EditStreamBuffer = malloc(4096 * sizeof(USHORT));
  1715.         EditStreamMaxLen = 4096;
  1716.         EditStreamLen = 0;
  1717.     }
  1718.  
  1719.     if ( EditStreamLen < EditStreamMaxLen ) {
  1720.         static int found_cr = 0;
  1721.         if ( uch == CR ) {
  1722.             found_cr = 1;
  1723.             EditStreamBuffer[EditStreamLen++] = 0x2028;
  1724.         } else if ( uch == LF ) {
  1725.             if ( !found_cr )
  1726.                 EditStreamBuffer[EditStreamLen++] = 0x2028;
  1727.             found_cr = 0;
  1728.         } else {
  1729.             EditStreamBuffer[EditStreamLen++] = uch;
  1730.             found_cr = 0;
  1731.         }
  1732.     } else {
  1733.         ReleaseRichEditMutex();
  1734.         Sleep(100);
  1735.         goto start;
  1736.     }
  1737.     ReleaseRichEditMutex();
  1738.     return 0;
  1739. }
  1740.  
  1741. int
  1742. gui_text_popup_close(void)
  1743. {
  1744.     if ( hwndTextDlg != INVALID_HANDLE_VALUE )
  1745.         PostMessage(hwndTextDlg, WM_CLOSE, 0, 0);
  1746.     CloseRichEditCloseSem();
  1747.     CloseRichEditMutex();
  1748.     free(EditStreamBuffer);
  1749.     EditStreamBuffer = NULL;
  1750.     EditStreamLen = EditStreamMaxLen = 0;
  1751.     return 0;
  1752. }
  1753.  
  1754. int
  1755. gui_text_popup_wait(int seconds)
  1756. {
  1757.     RequestRichEditMutex(INFINITE);
  1758.     stream_complete = 1;
  1759.     ReleaseRichEditMutex();
  1760.  
  1761.     if ( hwndRichEdit != INVALID_HANDLE_VALUE ) {
  1762.         WaitRichEditCloseSem(seconds == -1 ? INFINITE : seconds * 1000);
  1763.         return 0;
  1764.     }
  1765.     return -1;
  1766. }
  1767. #endif /* KUI */
  1768.