/********************************************************************** * * fnord.cpp * Copyright (C) 1996 * * A component of the fnord webserver written by bmorin@wpi.edu. * * Altered for use with the Greenstone digital library software by the * New Zealand Digital Library Project at the University of Waikato, * New Zealand. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ #include "text_t.h" #include #include #include #include #include #pragma hdrstop #include "netio.h" #include "settings.h" #include "httpsrv.h" #include "resource.h" #include "locate.h" #include "cgiwrapper.h" #include "startbrowser.h" #include "d_winsock.h" #include "fileutil.h" #define MAINWINDOWWIDTH 400 #define MAINWINDOWHEIGHT 200 #define WASTEHEIGHT 44 // Error in ht due to caption and menu bar #define WASTEWIDTH 6 #define SPACERWIDTH 5 // size and position of the collection title #define COLTITLEWIDTH 351 #define COLTITLEHEIGHT 35 #define COLTITLEX ((MAINWINDOWWIDTH-COLTITLEWIDTH)/2) #define COLTITLEY 10 // size and position of the version string #define VERSIONWIDTH MAINWINDOWWIDTH #define VERSIONHEIGHT 20 #define VERSIONX 0 #define VERSIONY (COLTITLEY+COLTITLEHEIGHT) // size and position of the Greenstone digital library logo #define LOGOWIDTH 135 #define LOGOHEIGHT 55 #define LOGOX (MAINWINDOWWIDTH-(LOGOWIDTH+SPACERWIDTH)) #define LOGOY (MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH)) // size and position of the enter button #define ENTERBUTTONWIDTH 160 #define ENTERBUTTONHEIGHT 30 #define ENTERBUTTONX SPACERWIDTH #define ENTERBUTTONY ((MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))-(ENTERBUTTONHEIGHT+SPACERWIDTH)) // size and position of the enter string #define ENTERSTRINGX (ENTERBUTTONX+ENTERBUTTONWIDTH+SPACERWIDTH) #define ENTERSTRINGY ENTERBUTTONY #define ENTERSTRINGWIDTH (MAINWINDOWWIDTH-(ENTERBUTTONWIDTH+SPACERWIDTH+SPACERWIDTH+SPACERWIDTH)) #define ENTERSTRINGHEIGHT ENTERBUTTONHEIGHT // size and position of the info string #define INFOWIDTH MAINWINDOWWIDTH #define INFOHEIGHT (MAINWINDOWHEIGHT-INFOY) #define INFOX 0 #define INFOY ENTERBUTTONY // size and position of restricted buttons #define ALTERNATIVEBUTTONWIDTH 160 #define ALTERNATIVEBUTTONHEIGHT 30 #define ALTERNATIVEBUTTONX SPACERWIDTH #define ALTERNATIVEBUTTONY LOGOY #define INFOBUTTONWIDTH 30 // size and position of restart button #define RESTARTBUTTONWIDTH 160 #define RESTARTBUTTONHEIGHT 30 #define RESTARTBUTTONX 50 #define RESTARTBUTTONY (MAINWINDOWHEIGHT-RESTARTBUTTONHEIGHT-15) // constant for restart/reconfigure windows message (same as in recpt/configaction.cpp) // http://msdn.microsoft.com/en-us/library/ms644931%28v=VS.85%29.aspx on WM_USER // (also RegisterWindowMessage Function at http://msdn.microsoft.com/en-us/library/ms644947%28v=VS.85%29.aspx // http://msdn.microsoft.com/en-us/library/ms644927%28v=VS.85%29.aspx) #define WM_RESTART WM_USER+1 const char versionstring[] = "version " GSDL_VERSION; const char strnothing[] = ""; const char strinit[] = "Initialising..."; const char strsb[] = "Starting browser..."; const char strrestartlib[] = "Press the 'Restart Library' button to start a browser\n" "and enter library"; const char strenterlib[] = "Press this button to begin using\n" "the library"; const char *enterstring = NULL; // points to the current enter string const char *infostring = NULL; // points to the current info string // globals to do with networking and browsers int have_networking = 0; int netscapeneeded = 0; char startbrowserdir[1024] = ""; // HARD LIMIT!!!!! // stats to do with the last time the enter library button was pressed // these stats are needed to make suggestions about the proxy int enterlib_libaccessnum = -1; // -1 = NA DWORD enterlib_time = 0; enum { undefined_window, console_window, plain_window } window_state; HDC coltitledc = NULL; HBITMAP defcoltitlebitmap = NULL, coltitlebitmap=NULL; HDC logodc=NULL; HBITMAP deflogobitmap=NULL, logobitmap=NULL; HWND GoButton = NULL; HWND Enter = NULL; // HWND EnterRestricted = NULL; // HWND InfoRestricted = NULL; int init_type = 0; int init_done = 0; // Added an argument so you can specify not to do any of the windows orientated clean up - jmt12 18/11/2003 void finish_up(bool init_only) { // remember the current preferences write_settings(""); if(init_only) { return; } // Shutdown the HTTP server EndHTTPServer(); // Shutdown the main server modules CleanUpNetIO(); // RemoveFnordFromTray(); // Unload the wsock32 dll d_UnloadWinsock(); // Clean up graphics stuff from window if (defcoltitlebitmap != NULL) SelectObject (coltitledc, defcoltitlebitmap); if (coltitlebitmap != NULL) DeleteObject (coltitlebitmap); if (coltitledc != NULL) DeleteDC (coltitledc); if (deflogobitmap != NULL) SelectObject (logodc, deflogobitmap); if (logobitmap != NULL) DeleteObject (logobitmap); if (logodc != NULL) DeleteDC (logodc); // Shutdown the main window PostQuitMessage(0); } int overlap(int left, int top, int right, int bottom, RECT &r2) { if (left <= r2.right && r2.left <= right && top <= r2.bottom && r2.top <= bottom) return 1; else return 0; } void paint_window (HDC pdc, RECT &updateRect) { // make sure the various DCs are set up if (coltitledc == NULL) { coltitledc = CreateCompatibleDC(pdc); defcoltitlebitmap = (HBITMAP)SelectObject (coltitledc, coltitlebitmap); } if (logodc == NULL) { logodc = CreateCompatibleDC(pdc); deflogobitmap = (HBITMAP)SelectObject (logodc, logobitmap); } // remove any remaining sign of initial buttons if (init_done && (overlap (ENTERBUTTONX, ENTERBUTTONY, ENTERBUTTONX+ENTERBUTTONWIDTH, ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT, updateRect))) { RECT initRect; initRect.left = ENTERBUTTONX; initRect.top = ENTERBUTTONY; initRect.right = ENTERBUTTONX+ENTERBUTTONWIDTH; initRect.bottom = ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT; FillRect(pdc, &initRect, (HBRUSH)GetStockObject(WHITE_BRUSH)); } // update the collection title if needed if (overlap(COLTITLEX, COLTITLEY, COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT, updateRect)) { BitBlt (pdc, COLTITLEX, COLTITLEY, COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT, coltitledc, 0, 0, SRCCOPY); } // update the version string if needed if (overlap (VERSIONX, VERSIONY, VERSIONX+VERSIONWIDTH, VERSIONY+VERSIONHEIGHT, updateRect)) { RECT versionRect; versionRect.left = VERSIONX; versionRect.top = VERSIONY; versionRect.right = VERSIONX+VERSIONWIDTH; versionRect.bottom = VERSIONY+VERSIONHEIGHT; DrawText(pdc, versionstring, -1, &versionRect, DT_CENTER); } // decide what we want to draw if (init_done && gsdl_show_console) { // we want to draw a "console" window if (window_state != console_window || overlap (text_rect.left, text_rect.top, text_rect.right, text_rect.bottom, updateRect)) { refresh_console (pdc); } window_state = console_window; } else { // we want to draw a "plain" window // update the enter string if needed if (overlap (ENTERSTRINGX, ENTERSTRINGY, ENTERSTRINGX+ENTERSTRINGWIDTH, ENTERSTRINGY+ENTERSTRINGHEIGHT, updateRect)) { RECT enterstringRect; enterstringRect.left = ENTERSTRINGX; enterstringRect.top = ENTERSTRINGY; enterstringRect.right = ENTERSTRINGX+ENTERSTRINGWIDTH; enterstringRect.bottom = ENTERSTRINGY+ENTERSTRINGHEIGHT; FillRect(pdc, &enterstringRect, (HBRUSH)GetStockObject(WHITE_BRUSH)); if ((enterstring != NULL) && (strlen(enterstring) > 0)) { int cury = ENTERSTRINGY; int startline = 0, here = 0; while (enterstring[here] != '\0') { if (enterstring[here] < ' ') { if (here - startline > 0) { // output the text TextOut (pdc, ENTERSTRINGX, cury, &enterstring[startline], here-startline); cury += line_spacing; } startline = here+1; } ++here; } // output any remaining text if (here - startline > 0) { TextOut (pdc, ENTERSTRINGX, cury, &enterstring[startline], here-startline); } } } window_state = plain_window; } // update the info string if needed if (init_done && !gsdl_show_console && ((infostring != NULL) && overlap (INFOX, INFOY, INFOX+INFOWIDTH, INFOY+INFOHEIGHT, updateRect))) { RECT infoRect; infoRect.left = INFOX; infoRect.top = INFOY; infoRect.right = INFOX+INFOWIDTH; infoRect.bottom = INFOY+INFOHEIGHT; FillRect(pdc, &infoRect, (HBRUSH)GetStockObject(WHITE_BRUSH)); DrawText(pdc, infostring, -1, &infoRect, DT_CENTER); } // update the logo (always) BitBlt (pdc, LOGOX, LOGOY, LOGOX+LOGOWIDTH, LOGOY+LOGOHEIGHT, logodc, 0, 0, SRCCOPY); } void handle_painting (HWND Window) { HDC pdc; PAINTSTRUCT ps; pdc = BeginPaint(Window, &ps); paint_window (pdc, ps.rcPaint); EndPaint(Window, &ps); } // returns 1 on success, 0 otherwise int enter_library (HWND Window) { int res; if (infostring == strrestartlib) { // the "restart library" button was pressed so we want to reinitialize // greenstone, read in all the macrofiles again, etc. gsdl_init(false); } // get the url and attempt to start a browser if (have_networking) { // There are now four address resolution methods: // 0: Standard -- get local IP then resolve to a name // 1: IP only -- as above, but use IP only -- don't resolve to a name // 2: localhost -- always use localhost // 3: 127.0.0.1 -- always use 127.0.0.1 char gsdl_address[100]; char hostIP[25]; // 16 should be enough to represent an IP address + null byte DWORD local_ip = GetLocalIP(); // always work out the hostIP: sprintf(hostIP, "%d.%d.%d.%d", local_ip & 0xFF, (local_ip >> 8) & 0xFF, (local_ip >> 16) & 0xFF, (local_ip >> 24) & 0xFF); if (local_ip == INADDR_ANY || gsdl_address_resolution_method == 3) { local_ip = 127 + (0 << 8) + (0 << 16) + (1 << 24); } if (gsdl_address_resolution_method == 1 || gsdl_address_resolution_method == 3) { sprintf(gsdl_address, "%d.%d.%d.%d", local_ip & 0xFF, (local_ip >> 8) & 0xFF, (local_ip >> 16) & 0xFF, (local_ip >> 24) & 0xFF); } else if (gsdl_address_resolution_method == 2) { sprintf(gsdl_address, "localhost"); } else { strcpy(gsdl_address, GetLocalName(NULL)); } text_t url = "http://" + text_t(gsdl_address); gsdl_host_IP = text_t(hostIP); gsdl_url = url; write_settings(gsdl_url); if (gsdl_port_num != 80) { url += ":" + text_t(gsdl_port_num); } url += gsdl_enterlib; // add a unique ending so it will always result in a request text_t::const_iterator it = findchar (gsdl_enterlib.begin(), gsdl_enterlib.end(), '?'); if (it == gsdl_enterlib.end()) url.push_back ('?'); else url.push_back ('&'); int tcount = GetTickCount(); url += "uq=" + text_t(tcount); // remember the library access number for later proxy checking enterlib_libaccessnum = libaccessnum; if (gsdl_start_browser) { // do a quick check to make sure we're using netscape when // we should be (it might have been just installed) if (netscapeneeded) gsdl_check_browser_settings (netscapeneeded); char *cstr_url = url.getcstr(); if (strlen (startbrowserdir) <= 0) { res = startbrowser (cstr_url, gsdl_browser_exe, NULL); } else res = startbrowser (cstr_url, gsdl_browser_exe, startbrowserdir); delete []cstr_url; } else { return 1; } } if (res == SB_NOERROR) { // success !! // remember the time the browser was started for later proxy checking if (have_networking) enterlib_time = GetTickCount(); return 1; } // no browser was started enterlib_libaccessnum = -1; if ((res == SB_FAIL_BADFORMAT) || (res == SB_FAIL_NOTFOUND)) { if (!netscapeneeded) { // any browser MessageBox(Window, "Failed to start your chosen browser. It seems that your\n" "chosen browser has been removed or corrupted.\n" "Please check your browser choice by going to the\n" "'Settings...' item under the 'File' menu.", "Greenstone Digital Library Software", MB_OK); } else { // netscape used MessageBox(Window, "Failed to start Netscape. It seems that Netscape has\n" "been removed or corrupted. You need Netscape\n" "installed to use the Greenstone Digital Library\n" "software on non-networked machines.", "Greenstone Digital Library Software", MB_OK); } } else { MessageBox(Window, "Failed to start your browser. This may have been\n" "because there was not enough memory available. Shut\n" "down all other applications you have running, and\n" "try again.", "Greenstone Digital Library Software", MB_OK); } return 0; // failed } void install_netscape (HWND Window) { char installpath[256]; // try to find the browser directory char *gsdlhome = gsdl_gsdlhome.getcstr(); strcpy (installpath, gsdlhome); // use gsdlhome to find the CD-ROM drive... delete []gsdlhome; // remove any slashes from the pathname int len = strlen (installpath); while ((len > 0) && ((installpath[len-1] == '\\') || (installpath[len-1] == '/'))) { --len; } // remove '\gsdl' len = len - 5; installpath[len] = '\0'; strcat (installpath, "\\netscape\\"); // check this directory if (!cstrcheckdir(installpath)) { return; } // get the operating system information OSVERSIONINFO osver; memset(&osver, 0, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); // get the install program for this operating system if (osver.dwPlatformId == VER_PLATFORM_WIN32s) { strcat (installpath, "n16e405.exe"); } else { strcat (installpath, "n32e405.exe"); } // run the install program int res = WinExec (installpath, SW_SHOW); if (res == 0) { // out of resources or memory MessageBox (Window, "Did not have enough resources or memory to run the\n" "install program. Try shutting down all other programs\n" "and trying again.", "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL); } else if (res == ERROR_BAD_FORMAT) { // executable image is corrupt -- ???? MessageBox (Window, "The install program seems to be corrupt.", "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL); } else if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) { // couldn't find the executable -- ???? MessageBox (Window, "Could not find the install program. Try installing\n" "Netscape from the Greenstone Digital Library\n" "software's install program.", "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL); } } void open_help () { char topdir[256], cmd[256]; // try to find the browser directory char *gsdlhome = gsdl_gsdlhome.getcstr(); strcpy (topdir, gsdlhome); // use gsdlhome to find the CD-ROM drive... delete []gsdlhome; strcpy (cmd, "notepad "); // remove any slashes from the pathname int len = strlen (topdir); while ((len > 0) && ((topdir[len-1] == '\\') || (topdir[len-1] == '/'))) { --len; } // remove the '\gsdl' len = len - 5; topdir[len] = '\0'; strcat (topdir, "\\README.txt"); strcat (cmd, topdir); WinExec (cmd, SW_SHOW); } long __stdcall WndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) { switch(Message) { // Constant Messages case WM_CREATE: break; case WM_COMMAND: if ((GoButton != NULL) && ((HWND)LParam == GoButton)) { // attempt to start a browser gsdl_start_browser = 1; if (enter_library (Window) && !gsdl_show_console) ShowWindow(Window,SW_MINIMIZE); } else if ((Enter != NULL) && ((HWND)LParam == Enter)) { init_done = 1; init_type = 1; // } else if ((EnterRestricted != NULL) && ((HWND)LParam == EnterRestricted)) { // init_done = 1; // init_type = 0; // } else if ((InfoRestricted != NULL) && ((HWND)LParam == InfoRestricted)) { // MessageBox (NULL, "The Greenstone system automatically determines whether your computer has\n" // "network software installed or is connected to a network. It operates correctly\n" // "under any of these conditions.\n\n" // "The restricted version is intended for use when the standard one\n\n" // " (a) causes an unwanted telephone dialup operation;\n" // " (b) fails to run because network software is installed, but installed\n" // " incorrectly.\n\n" // "The restricted version only works with Netscape (not Internet Explorer).\n\n" // "Unless these problems arise, you should always use the standard version\n" // "(press the 'Enter Library' button).\n", // "Greenstone Digital Library Software", // MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); } else { switch (LOWORD(WParam)) { case ID_PROJECT_SETTINGS: Settings_Dialog(Window, netscapeneeded); break; case ID_INSTALL_NETSCAPE: install_netscape(Window); break; case IDHELP: open_help(); break; case ID_PROJECT_EXIT: finish_up(false); break; default: break; } } break; case WM_PAINT: handle_painting(Window); break; case HTTP_SERVER_MSG: ProcessHTTPServerMsg(WParam, LParam); break; case WM_DESTROY: finish_up(false); break; default: //Unhandled Messages end up here (DefWindowProc) return DefWindowProc(Window, Message, WParam, LParam); } return(0); } // returns 0 if successful, // otherwise a WSA error number int tryinitnetwork (HANDLE Instance, HWND MsgWindow, char *path) { // try to load winsock int err = d_LoadWinsock (path); if (err == D_NOERROR) { // next, try to init netio err = InitNetIO(); if (err == 0) { // next, try to start the http server err = StartHTTPServer(MsgWindow); if (err == 0) { // finally, get the host name (no error value // is returned from this function) GetLocalName((HINSTANCE)Instance); } else { // couldn't start the http server, // deinit netio and unload winsock CleanUpNetIO(); d_UnloadWinsock(); } } else { // couldn't init netio, unload winsock d_UnloadWinsock(); } } else { // couldn't load winsock err = WSASYSNOTREADY; } return err; } // inits all the network functionality // returns 0 if an unrecoverable error occurred, // and 1 if everything successfully initialised. int initnetwork (HANDLE Instance, HWND MsgWindow) { OSVERSIONINFO osver; // get the operating system information memset(&osver, 0, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); // first try to initialise the network with system installed // networking software startbrowserdir[0] = '\0'; netscapeneeded = 0; int err = 1; if (init_type == 1) err = tryinitnetwork (Instance, MsgWindow, NULL); // if an error occurred, try again with billsock if (err != 0) { // get the path of billsock (current directory + ("net16" | "net32")) char winsockpath[1024]; // HARD LIMIT!!!! find_location(); char *data_location_c = data_location.getcstr(); strcpy (winsockpath, data_location_c); delete []data_location_c; // remove all the slashes at the end of billpath int len = strlen (winsockpath); while ((len > 0) && ((winsockpath[len-1] == '\\') || (winsockpath[len-1] == '/'))) { --len; } winsockpath[len] = '\0'; if (osver.dwPlatformId == VER_PLATFORM_WIN32s) strcat (winsockpath, "\\net16\\"); else { strcat (winsockpath, "\\net32\\"); strcpy (startbrowserdir, winsockpath); } // try again err = tryinitnetwork (Instance, MsgWindow, winsockpath); if (err == 0) { // we will need to use netscape on 95/98/NT machines if (osver.dwPlatformId != VER_PLATFORM_WIN32s) { netscapeneeded = 1; // make sure the browser state is in step with the network condition gsdl_check_browser_settings (netscapeneeded); } // check to see if a browser is running if (browserrunning(gsdl_browser_exe) == NO_ERROR) { MessageBox (NULL, "The Greenstone Digital Library software has detected a\n" "running browser. To let our networking software\n" "correctly initialize, please shut down your browser\n" "and restart the Greenstone Digital Library software.", "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL); PostMessage(MsgWindow,WM_CLOSE,0,0); finish_up(false); // will unload winsock exit(0); // nothing more to do } } } // if an error occurred display a nice error message if (err != 0) { // WSASYSNOTREADY Couldn't load winsock // WSAVERNOTSUPPORTED The version of Windows Sockets support requested // is not provided by this particular Windows Sockets implementation. // WSAEINVAL The Windows Sockets version specified by the application // is not supported by this DLL. // WSAEPROTONOSUPPORT The specified protocol is not supported. // WSAEPROTOTYPE The specified protocol is the wrong type for this socket. // WSAESOCKTNOSUPPORT The specified socket type is not supported in // this address family. // WSANOTINITIALISED A successful WSAStartup must occur before // using this function. // WSAENETDOWN The Windows Sockets implementation // has detected that the network subsystem has failed. // WSAEADDRINUSE The specified address // is already in use. (See the SO_REUSEADDR socket option under setsockopt.) // WSAEFAULT The namelen argument is too small (less // than the size of a struct sockaddr). // WSAEINPROGRESS A blocking Windows Sockets call is in progress. // WSAEAFNOSUPPORT The specified address family is not supported // by this protocol. // WSAENOBUFS Not enough buffers available, too many connections. // WSAENOTSOCK The descriptor is not a socket. // WSAEISCONN The socket is already connected. // WSAEMFILE No more file descriptors are available. // WSAEOPNOTSUPP The referenced socket is not of a type that // supports the listen operation. // get a text version of the error number char errstr[256]; switch (err) { case WSASYSNOTREADY: strcpy(errstr, "WSASYSNOTREADY"); break; case WSAVERNOTSUPPORTED: strcpy (errstr, "WSAVERNOTSUPPORTED"); break; case WSAEINVAL: strcpy (errstr, "WSAEINVAL"); break; case WSAEPROTONOSUPPORT: strcpy (errstr, "WSAEPROTONOSUPPORT"); break; case WSAEPROTOTYPE: strcpy (errstr, "WSAEPROTOTYPE"); break; case WSAESOCKTNOSUPPORT: strcpy (errstr, "WSAESOCKTNOSUPPORT"); break; case WSANOTINITIALISED: strcpy (errstr, "WSANOTINITIALISED"); break; case WSAEFAULT: strcpy (errstr, "WSAEFAULT"); break; case WSAEAFNOSUPPORT: strcpy (errstr, "WSAEAFNOSUPPORT"); break; case WSAENOTSOCK: strcpy (errstr, "WSAENOTSOCK"); break; case WSAEISCONN: strcpy (errstr, "WSAEISCONN"); break; case WSAEOPNOTSUPP: strcpy (errstr, "WSAEOPNOTSUPP"); break; case WSAENETDOWN: strcpy (errstr, "WSAENETDOWN"); break; case WSAEADDRINUSE: strcpy (errstr, "WSAEADDRINUSE"); break; case WSAEINPROGRESS: strcpy (errstr, "WSAEINPROGRESS"); break; case WSAENOBUFS: strcpy (errstr, "WSAENOBUFS"); break; case WSAEMFILE: strcpy (errstr, "WSAEMFILE"); break; default: sprintf (errstr, "WSA ERROR: %i", err); break; } // create a nice error message char message[2048]; switch (err) { case WSAEADDRINUSE: // couldn't bind socket sprintf (message, "Could not find a free socket.", errstr); break; default: // cannot init winsock sprintf (message, "Could not initialize the network\n" " (Reason: %s).", errstr); break; } strcat (message, "\n\n" "Please submit a bug report using the support.htm file\n" "on the CD-ROM."); MessageBox (NULL, message, "Greenstone Digital Library Software", MB_OK); } return (err == 0); } void log_computer_info () { char tmpstr[1024]; // get various information about this computer if (gsdl_keep_log || gsdl_show_console) { // get operating system information OSVERSIONINFO osver; osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osver)) { if (osver.dwPlatformId == VER_PLATFORM_WIN32s) { log_message ("Platform: win32s\n"); } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { log_message ("Platform: windows 95\n"); } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { log_message ("Platform: windows NT\n"); } sprintf (tmpstr, "MajorVersion: %i\n", (int)osver.dwMajorVersion); log_message(tmpstr); sprintf (tmpstr, "MinorVersion: %i\n", (int)osver.dwMinorVersion); log_message(tmpstr); sprintf (tmpstr, "BuildNumber: %i\n", (int)osver.dwBuildNumber); log_message(tmpstr); sprintf (tmpstr, "CSDVersion: %s\n\n", osver.szCSDVersion); log_message(tmpstr); } // get memory information MEMORYSTATUS memstatus; memstatus.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus(&memstatus); sprintf (tmpstr, "TotalPhys: %i Meg\n", (int)(memstatus.dwTotalPhys/1024/1024)); log_message (tmpstr); sprintf (tmpstr, "AvailPhys: %i Meg\n", (int)(memstatus.dwAvailPhys/1024/1024)); log_message (tmpstr); sprintf (tmpstr, "TotalPageFile: %i Meg\n", (int)(memstatus.dwTotalPageFile/1024/1024)); log_message (tmpstr); sprintf (tmpstr, "AvailPageFile: %i Meg\n", (int)(memstatus.dwAvailPageFile/1024/1024)); log_message (tmpstr); sprintf (tmpstr, "TotalVirtual: %i Meg\n", (int)(memstatus.dwTotalVirtual/1024/1024)); log_message (tmpstr); sprintf (tmpstr, "AvailVirtual: %i Meg\n\n", (int)(memstatus.dwAvailVirtual/1024/1024)); log_message (tmpstr); // log the version number log_message("GSDL version: " GSDL_VERSION "\n"); } } // possible command line options are // --location=directory (the path to GSDLHOME which defaults to the // directory where server.exe lives) // --mode=gli (when server.exe is run from GLI). If GLI, "gli." is // the prefix used to load autoenter and start_browser properties // (gli.autoenter, gli.start_browser) from the config file // --config=file (the path to the configuration file to use which defaults // to GSDLHOME\llssite.cfg) // --cmd=init Used to initialize the llssite.cfg file only - jmt12 18/11/2003 static void parse_args(const text_t cmdline, text_t &location, text_t &mode, text_t &config_file, text_t &command) { location.clear(); config_file.clear(); mode.clear(); command.clear(); // jmt12 18/11/2003 if (cmdline.size() < 4) return; text_t name, val; bool foundname = false; text_t::const_iterator here = cmdline.begin(); text_t::const_iterator end = cmdline.end(); while (here != end) { if (*here == '-' && ((here+1) != end) && (*(here+1) == '-')) { ++here; if (name == "location") { location = val; } else if(name == "mode") { mode = val; } else if (name == "config") { config_file = val; } else if(name == "cmd") { // jmt12 18/11/2003 command = val; } foundname = false; name.clear(); val.clear(); } else if (*here == '=') { foundname = true; } else { if (foundname) { val.push_back(*here); } else { name.push_back(*here); } } ++here; } if (name == "location") { location = val; } else if (name == "mode") { mode = val; } else if (name == "config") { config_file = val; } else if(name == "cmd") { // jmt12 18/11/2003 command = val; } } // Tries to generate llssite.cfg from llssite.cfg.in in directory given // by location variable (assumes location is GSDLHOME), if llssite.cfg is missing void ensure_llssite_cfg(const text_t location) { text_t configfile = location+"\\llssite.cfg"; text_t configtemplate = location+"\\llssite.cfg.in"; if(!file_exists (configfile)) { if(file_exists (configtemplate)) { // try creating llssite.cfg from the template configfile llssite.cfg.in // by using a straightforward copy file_copy(configtemplate, configfile); } } } // Added code to allow for an 'init' run of the server which just creates the llssite.cfg file int __stdcall WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) { HWND MainWindow; MSG Message; WNDCLASS MainClass; // One instance of the local library server is quite enough, thank you very much HWND gw = FindWindow("Greenstone Digital Library Software", "Greenstone Digital Library Software"); if (gw != NULL) { exit(1); } // parse arguments text_t location, mode, config_file, command; parse_args(CmdLineStr, location, mode, config_file, command); gsdl_conffile = config_file; if (mode.empty()) { // if the server is run on its own, mode_prefix is "" with no '.' suffix gsdl_mode_property_prefix = ""; } else { // if the server is launched from GLI, the mode_prefix is "gli" and needs // '.' suffixed when accessing certain properties from the config file. gsdl_mode_property_prefix = trim(mode) + "."; } // Try to generate the llssite.cfg file if it's missing ensure_llssite_cfg(location); // jmt12 18/11/2003 if(command == "init") { // init various modules read_settings(0); // don't know if netscape is needed at this point finish_up(true); exit(0); } //Create a window class MainClass.style = CS_HREDRAW | CS_VREDRAW; MainClass.lpfnWndProc = WndProc; MainClass.cbClsExtra = 0; MainClass.cbWndExtra = 0; MainClass.hInstance = Instance; MainClass.hIcon = LoadIcon(Instance, MAKEINTRESOURCE(TRAY_ICON)); MainClass.hCursor = LoadCursor(NULL, IDC_ARROW); MainClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); MainClass.lpszMenuName = MAKEINTRESOURCE(Main_Menu); MainClass.lpszClassName = "Greenstone Digital Library Software"; if (!RegisterClass(&MainClass)) return 0; // Load various bitmaps coltitlebitmap = LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_COL_TITLE)); logobitmap= LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_LOGO)); // Create the main window MainWindow = CreateWindow("Greenstone Digital Library Software", "Greenstone Digital Library Software", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, MAINWINDOWWIDTH + WASTEWIDTH, MAINWINDOWHEIGHT + WASTEHEIGHT, NULL, NULL, Instance, NULL); text_rect.left = 0; text_rect.top = VERSIONY+VERSIONHEIGHT + 5; text_rect.right = MAINWINDOWWIDTH; text_rect.bottom = LOGOY-SPACERWIDTH; window_state = undefined_window; ShowWindow(MainWindow, SW_SHOW); set_location(location); // get ready to draw the main window RECT windowRect; GetClientRect (MainWindow, &windowRect); HDC pdc = GetDC (MainWindow); // retrieve and save the text metrics TEXTMETRIC tm; GetTextMetrics(pdc, &tm); line_spacing = tm.tmHeight + tm.tmExternalLeading; GSDL_Window = MainWindow; // init various modules read_settings (0); // don't know if netscape is needed at this point if (!gsdl_auto_enter) { // add the select version checkbox Enter = CreateWindow("BUTTON", // predefined class "Enter Library", // button text WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_DEFPUSHBUTTON, // styles ENTERBUTTONX, // starting x position ENTERBUTTONY, // starting y position ENTERBUTTONWIDTH, // button width ENTERBUTTONHEIGHT, // button height MainWindow, // parent window NULL, // No menu Instance, NULL); // pointer not needed // EnterRestricted = CreateWindow("Button", // predefined class // "Restricted Version", // button text // WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_PUSHBUTTON, // styles // ALTERNATIVEBUTTONX, // starting x position // ALTERNATIVEBUTTONY, // starting y position // ALTERNATIVEBUTTONWIDTH-(INFOBUTTONWIDTH+SPACERWIDTH), // button width // ALTERNATIVEBUTTONHEIGHT, // button height // MainWindow, // parent window // (HMENU)NULL, // No menu // Instance, // NULL); // pointer not needed // InfoRestricted = CreateWindow("Button", // predefined class // NULL, // WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_BITMAP, // styles // ALTERNATIVEBUTTONWIDTH-INFOBUTTONWIDTH+SPACERWIDTH, // starting x position // ALTERNATIVEBUTTONY, // starting y position // INFOBUTTONWIDTH, // button width // ALTERNATIVEBUTTONHEIGHT, // button height // MainWindow, // parent window // (HMENU)NULL, // No menu // Instance, // NULL); // pointer not needed // HANDLE i_icon = LoadImage (Instance, MAKEINTRESOURCE(GSDL_ICBMP), IMAGE_BITMAP, // INFOBUTTONWIDTH-4, ALTERNATIVEBUTTONHEIGHT-4, LR_DEFAULTCOLOR); // SendMessage (InfoRestricted, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)i_icon); SetFocus (Enter); // Since we have not entered the library yet, set the URL in the configfile to pending state gsdl_url = "URL_pending"; write_settings(gsdl_url); enterstring = strenterlib; paint_window (pdc, windowRect); // message loop for init buttons while (!init_done) { if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) { if (Message.message == WM_QUIT) return Message.wParam; if (!IsDialogMessage (MainWindow, &Message)) { TranslateMessage(&Message); /* translate keyboard messages */ DispatchMessage(&Message); /* return control to Windows NT */ } } else { Sleep (1); } } // don't want these buttons anymore DestroyWindow (Enter); // DestroyWindow (EnterRestricted); // DestroyWindow (InfoRestricted); enterstring = strnothing; paint_window (pdc, windowRect); } else { // auto enter is enabled - start up standard version init_type = 1; init_done = 1; } // draw the main window containing an init message infostring = strinit; paint_window (pdc, windowRect); DWORD lastcheck = GetTickCount(); have_networking = initnetwork (Instance, MainWindow); if (!have_networking) { MessageBox(NULL, "Failed to initialize networking.", "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL); exit (0); } if (!gsdl_init()) // quit if can't initialise the library correctly exit (0); initstartbrowser(); log_computer_info (); // show the initialising message for at least 1 second while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) { Sleep (1); } // attempt to start a browser if (gsdl_show_console || !gsdl_start_browser) infostring = strnothing; else infostring = strsb; paint_window (pdc, windowRect); lastcheck = GetTickCount(); if (enter_library (MainWindow) && !gsdl_show_console) { // stay maximised for at least 1 second while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) Sleep (1); ShowWindow(MainWindow,SW_MINIMIZE); } // add the "restart library" button GoButton = CreateWindow("BUTTON", // predefined class "Restart Library", // button text WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // styles RESTARTBUTTONX, // starting x position RESTARTBUTTONY, // starting y position RESTARTBUTTONWIDTH, // button width RESTARTBUTTONHEIGHT, // button height MainWindow, // parent window NULL, // No menu Instance, NULL); // pointer not needed infostring = strrestartlib; paint_window (pdc, windowRect); // release the DC used to display the init messages ReleaseDC (MainWindow, pdc); //Message loop lastcheck = GetTickCount(); int seenbrowser = 0; // if we see a browser then it disappears // we will ask if they want to close the // the library down char last_gsdl_browser_exe[MAX_FILENAME_SIZE]; // need to notice when the // browser setting changes strcpy (last_gsdl_browser_exe, gsdl_browser_exe); for (;;) { if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) { if (Message.message == WM_QUIT) { break; } if (Message.message == WM_RESTART) { read_settings(0); if (!gsdl_init(false)) { // do the same as when restart library is pressed MessageBox(NULL,"Error re-initializing gsdl: gsdl_init()", "Error initialising GSDL", MB_OK|MB_SYSTEMMODAL); // when Restart Library is pressed, exit(0) is called) but a break here // will exit Greenstone same as with WM_QUIT msg above break; } } if (!IsDialogMessage (MainWindow, &Message)) { TranslateMessage(&Message); /* translate keyboard messages */ DispatchMessage(&Message); /* return control to Windows NT */ } } else { if (DiffTickCounts (lastcheck, GetTickCount()) > 500) { // make sure the browser hasn't changed if (strcmp (last_gsdl_browser_exe, gsdl_browser_exe) != 0) { seenbrowser = 0; strcpy (last_gsdl_browser_exe, gsdl_browser_exe); } // do check lastcheck = GetTickCount(); if (gsdl_start_browser && browserrunning(gsdl_browser_exe) == NO_ERROR) { // we were able to connect to a browser seenbrowser = 1; // see if the enter library button has been pressed // with nothing happening for 20 seconds if ((enterlib_libaccessnum >= 0) && (enterlib_libaccessnum == libaccessnum) && (DiffTickCounts (enterlib_time, GetTickCount()) > 20000)) { // something could be wrong!! (most likely cause is a proxy) MessageBox(NULL, "Your browser does not seem to be responding to the 'Enter Library'\n" "request. Try turning off all proxy servers in your browser settings.\n" "If you are using Internet Explorer make sure BOTH dialup settings\n" "AND LAN settings have their proxy servers disabled.", "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL); enterlib_libaccessnum = -1; } } else { // no browser was found if (seenbrowser) { // we have seen a browser in the past if (MessageBox(NULL, "The Greenstone Digital Library software has noticed that you\n" "shut down your browser. Would you also like to shut down the\n" "Greenstone Digital Library software?", "Greenstone Digital Library Software",MB_YESNO|MB_SYSTEMMODAL) == IDYES) PostMessage(MainWindow,WM_CLOSE,0,0); } seenbrowser = 0; } } Sleep (1); // millisecond } } return Message.wParam; }