--- /dev/null
+/*
+ * install.c (c) 1998,1999 Brian Smith
+ * parts by Daniele Vistalli
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <fcntl.h>
+#if defined(__OS2__) || defined(__EMX__) || defined(WINNT) || defined(WIN32)
+#include <process.h>
+#endif
+#include <sys/types.h>
+#include "install.h"
+#include "instsup.h"
+
+#if !defined(__EMX__) && !defined(__OS2__) && !defined(WIN32) && !defined(WINNT)
+#define stricmp strcasecmp
+#endif
+
+/* My Global variables ;) unusually many due to multiple dialogs */
+char tempPath[MAX_PATH];
+int installstate = NONE;
+int installstage = 0;
+int current_file=0, success=0;
+unsigned long int acepos=0, aceoffset=0;
+int pixels=0;
+char confirmstring[1024];
+/* I know I am being excessive but... better safe than sorry ;) */
+char *configsys[8196];
+int configfilecount=-1;
+int files = 0, files_deleted=0, packagesize=0, packagesselected[20];
+/* Global flags often set by the user */
+int driveselected, packagechosen, express = 1, driverstatus = -1, no_update = 0;
+int licensechecked = 0, custom = 0, checkforupdate = 1, downloadsite = 0;
+int usescitech = 1, usecurrent = 0, checking = 0, checkerror = 0, newerver = 0;
+char sddfilename[256] = "", sddversion[256] = "", sdddate[256] = "";
+char sddurl[4][256] = { "", "", "", "" };
+
+/* So these are accessible to REXX */
+int drivelist[26];
+FILE *self;
+
+/* These get loaded in loadheader */
+char *INSTALLER_APPLICATION;
+char *INSTALLER_VERSION;
+char *INSTALLER_TITLE;
+char *INSTALLER_PATH;
+char *INSTALLER_FOLDER;
+char *INSTALLER_PROGRAM;
+char *INSTALLER_SHADOW;
+char *INSTALLER_OBJECT;
+char *INSTALLER_SETS;
+char *INSTALLER_SYSVAR;
+char *INSTALLER_SYSLINE;
+char *INSTALLER_PACKAGES[20];
+char *INSTALLER_CONFIRM_WPS;
+char *INSTALLER_CONFIRM_CONFIGSYS;
+char *INSTALLER_CONFIRM_OVERWRITE;
+int INSTALLER_PACKAGE_COUNT;
+
+/* Will have to seperate this stuff to platform specifics... */
+
+/* Config.Sys -- Note the drive letter gets replaced with the boot drive letter
+ It is just a place holder. (For the next 3 entries) */
+char csfile[] = "C:\\CONFIG.SYS";
+/* Backup Config.Sys filename */
+char bufile[] = "C:\\CONFIG.SDD";
+/* Installation Log Database -- Used for uninstallation and aborting */
+#if defined(__OS2__) || defined(__EMX__) || defined(WINNT) || defined(WIN32)
+char instlog[] = "C:\\DBINST.LOG";
+#else
+char instlog[] = "~/dbinst.log";
+#endif
+char installdir[400];
+
+char bootdrive[2] = "C";
+char winpath[400] = "C:\\OS2\\MDOS\\WINOS2";
+char winjpath[400] = "C:\\OS2\\MDOS\\WINJOS2";
+char wintpath[400] = "C:\\OS2\\MDOS\\WINTOS2";
+char winhpath[400] = "C:\\OS2\\MDOS\\WINHOS2";
+char browsedir[400] = "C:\\";
+char installdir2[400] = "";
+char empty_string[] = "";
+char currentcf[400] = "";
+
+#ifdef ENABLE_LOGGING
+FILE *logfile;
+#endif
+
+/* Function prototypes */
+int installer_unpack(char *filename, int operation);
+void resetglobals(void);
+
+typedef struct _replacements {
+ char *replacestring, *replacevar;
+} Replacements;
+
+/* The variables in this array must be static buffers */
+Replacements InstRep[] = {
+ { "%INSTALLPATH%", installdir },
+ { "%BOOTDRIVE%", bootdrive },
+ { "%ANYSTRING%", empty_string },
+ { "%WINPATH%", winpath },
+ { "%WINJPATH%", winjpath },
+ { "%WINTPATH%", wintpath },
+ { "%WINHPATH%", winhpath },
+ { "%USERPATH%", installdir2 },
+ { "%VERSION%", "1.0" }, /* This may be depricated */
+ { "%WEB_VER%", sddversion },
+ { "%WEB_DATE%", sdddate },
+ { "%WEB_LOCATION1%", sddurl[0] },
+ { "%WEB_LOCATION2%", sddurl[1] },
+ { "%WEB_LOCATION3%", sddurl[2] },
+ { "%WEB_LOCATION4%", sddurl[3] },
+ { "%PRI%", "SVGA" }
+};
+int replacemax = 16;
+
+/* In str1, str2 gets replaced by str3 */
+char *replacestr(char *str1, char *str2, char *str3)
+{
+ char bigbuffer[4096];
+ int z, x=0, len1 = strlen(str1), len2 = strlen(str2), len3 = strlen(str3);
+
+ for(z=0;z<len1;z++)
+ {
+ if(len2 > 0 && strncmp(&str1[z], str2, len2)==0)
+ {
+ int i;
+ for(i=0;i<len3;i++)
+ {
+ bigbuffer[x] = str3[i];
+ x++;
+ }
+ z=z+(len2-1);
+ } else {
+ bigbuffer[x] = str1[z];
+ x++;
+ }
+ }
+ bigbuffer[x] = 0;
+ return (char *)strdup(bigbuffer);
+}
+
+/* This function parses a string and replaces all the text in the
+ * Replacement array with the current dynamic text */
+char *replaceem(char *orig)
+{
+ char *tmp1 = NULL, *tmp2 = (char *)strdup(orig);
+ int z;
+
+ for(z=0;z<replacemax;z++)
+ {
+ tmp1 = replacestr(tmp2, InstRep[z].replacestring, InstRep[z].replacevar);
+ free(tmp2);
+ tmp2 = tmp1;
+ tmp1 = NULL;
+ }
+ return tmp2;
+}
+
+/*
+ * Find the offset withing the executable of the ace data for use.
+ */
+int aceseek_entry(int num)
+{
+ long headerstart;
+ char headerbuf[20], packageconfig[100];
+ int z, start = 0, entry = 0, packageoffset=0;
+ /* Decode DBSOFT-ACE - small memleak but
+ * install should not be running for very long. :) */
+ sprintf(headerbuf, "%s%d", decode("EEECFDEPEGFECNEBEDEF"), num);
+ if((headerstart = findtext(headerbuf)) < 0)
+ {
+ mesg("Could not find ACE header in executable.");
+ exit(2);
+ }
+
+ fseek(self, headerstart+strlen(headerbuf), SEEK_SET);
+ fread(packageconfig, 1, 100, self);
+
+ for(z=0;z<100;z++)
+ {
+ if(packageconfig[z] == '-' || packageconfig[z] == '*')
+ {
+ char cur = packageconfig[z];
+ packageconfig[z] = 0;
+ switch(entry)
+ {
+ case 0:
+ current_file = 0;
+ files = atoi(&packageconfig[start]);
+ break;
+ case 1:
+ packagesize = atoi(&packageconfig[start]);
+ break;
+ }
+ start = z+1;
+ if(cur == '*')
+ {
+ packageoffset = z + 1;
+ z = 100;
+ }
+ entry++;
+ }
+ }
+ aceoffset=headerstart+strlen(headerbuf)+packageoffset;
+ fseek(self, aceoffset, SEEK_SET);
+ return TRUE;
+}
+
+/*
+ * Reads the embedded .cfg data from the executable and place it in the global
+ * INSTALL_* variables for use.
+ */
+int loadheader(void)
+{
+ char *buffer;
+ long headerstart;
+ int z, start=0, entry=0;
+
+ buffer = malloc(8096*4);
+
+ /* Decode DBSOFT-HEADER */
+ if((headerstart = findtext(decode("EEECFDEPEGFECNEIEFEBEEEFFC"))) < 0)
+ {
+ mesg("Could not find Selfinstaller header in executable.");
+ exit(2);
+ }
+ fseek(self, headerstart+13, SEEK_SET);
+
+ fread(buffer, 1, 8096*4, self);
+ for(z=0;z<8096*4;z++)
+ {
+ if(buffer[z] == '-' || buffer[z] == '*')
+ {
+ char cur = buffer[z];
+ buffer[z] = 0;
+ switch(entry)
+ {
+ case 0:
+ INSTALLER_APPLICATION = (char *)strdup(&buffer[start]);
+ break;
+ case 1:
+ INSTALLER_VERSION = (char *)strdup(&buffer[start]);
+ break;
+ case 2:
+ INSTALLER_TITLE = (char *)strdup(&buffer[start]);
+ break;
+ case 3:
+ INSTALLER_PATH = (char *)strdup(&buffer[start]);
+ break;
+ case 4:
+ INSTALLER_FOLDER = (char *)strdup(&buffer[start]);
+ break;
+ case 5:
+ INSTALLER_PROGRAM = (char *)strdup(&buffer[start]);
+ break;
+ case 6:
+ INSTALLER_SHADOW = (char *)strdup(&buffer[start]);
+ break;
+ case 7:
+ INSTALLER_OBJECT = (char *)strdup(&buffer[start]);
+ break;
+ case 8:
+ INSTALLER_SETS = (char *)strdup(&buffer[start]);
+ break;
+ case 9:
+ INSTALLER_SYSVAR = (char *)strdup(&buffer[start]);
+ break;
+ case 10:
+ INSTALLER_SYSLINE = (char *)strdup(&buffer[start]);
+ break;
+ case 11:
+ INSTALLER_CONFIRM_WPS = (char *)strdup(&buffer[start]);
+ break;
+ case 12:
+ INSTALLER_CONFIRM_CONFIGSYS = (char *)strdup(&buffer[start]);
+ break;
+ case 13:
+ INSTALLER_CONFIRM_OVERWRITE = (char *)strdup(&buffer[start]);
+ break;
+ case 14:
+ INSTALLER_PACKAGE_COUNT = atoi(&buffer[start]);
+ break;
+ default:
+ INSTALLER_PACKAGES[entry-15] = malloc((z-start)+1);
+ strcpy(INSTALLER_PACKAGES[entry-15], &buffer[start]);
+ break;
+ }
+ start = z+1;
+ if(cur == '*')
+ {
+ free(buffer);
+ return TRUE;
+ }
+
+ entry++;
+ }
+ }
+ free(buffer);
+ return FALSE;
+}
+
+/*
+ * Functions to work on an ace file embedded within the archive in an
+ * abstract manner.
+ */
+int aceread(void *buf, size_t count)
+{
+ unsigned long curpos = ftell(self);
+ size_t readit;
+
+ if(count > (packagesize-(curpos-aceoffset)))
+ readit = (packagesize-(curpos-aceoffset));
+ else
+ readit = count;
+
+ return fread(buf, 1, readit, self);
+}
+
+off_t acelseek(off_t offset, int whence)
+{
+ switch(whence)
+ {
+ case SEEK_SET:
+ fseek(self, aceoffset+offset, SEEK_SET);
+ break;
+ case SEEK_CUR:
+ fseek(self, offset, SEEK_CUR);
+ break;
+ }
+ acepos = ftell(self);
+ return acepos-aceoffset;
+}
+
+int aceopen(const char *path, int flags)
+{
+ fseek(self, aceoffset, SEEK_SET);
+ return 1;
+}
+
+int aceclose(int fd)
+{
+ fseek(self, aceoffset, SEEK_SET);
+ return 0;
+}
+
+int acesize(void)
+{
+ return packagesize;
+}
+
+int acetell(int fd)
+{
+ return ftell(self)-aceoffset;
+}
+
+/*
+ * Read the generated log file and remove any files installed.
+ */
+void delete_files(void)
+{
+ char tmpbuf[8196], *fileptr;
+ FILE *tmplf;
+ int linenum=0, found=-1, z;
+
+ files_deleted=1;
+
+ if((tmplf=fopen(instlog, "rb"))==NULL)
+ return;
+
+ while(!feof(tmplf))
+ {
+ fgets(tmpbuf, 8196, tmplf);
+ linenum++;
+ if(tmpbuf[0]=='[' && (char *)strstr(tmpbuf, INSTALLER_APPLICATION) != NULL && !feof(tmplf))
+ {
+ fgets(tmpbuf, 8196, tmplf);
+ linenum++;
+ if((char *)strstr(tmpbuf, "<Version>") != NULL && (char *)strstr(tmpbuf, INSTALLER_VERSION) != NULL)
+ found=linenum;
+ }
+ }
+ if(found != -1)
+ {
+ rewind(tmplf);
+ for (z=0;z<found;z++)
+ fgets(tmpbuf, 8196, tmplf);
+ while(!feof(tmplf))
+ {
+ fgets(tmpbuf, 8196, tmplf);
+ if((char *)strstr(tmpbuf, "<FileInst>") != NULL)
+ {
+ fileptr = (char *)strchr(tmpbuf, ',')+1;
+ /* Remove trailing CRLFs */
+ if(fileptr[strlen(fileptr)-1] == '\r' || fileptr[strlen(fileptr)-1] == '\n')
+ fileptr[strlen(fileptr)-1]=0;
+ if(fileptr[strlen(fileptr)-1] == '\r' || fileptr[strlen(fileptr)-1] == '\n')
+ fileptr[strlen(fileptr)-1]=0;
+ remove(fileptr);
+ current_file--;
+#if 0
+ sendmessage(0, 1);
+#endif
+ }
+ if((char *)strstr(tmpbuf, "<End>") != NULL)
+ {
+ fclose(tmplf);
+ return;
+ }
+ }
+ }
+ fclose(tmplf);
+ return;
+}
+
+/*
+ * Reads a config file into memory for editing with updatesys, updateset, etc.
+ */
+int readconfigfile(char *filename)
+{
+ char tmpbuf[8196];
+ FILE *tmpcs;
+
+ /* Reset this value when restarting */
+ configfilecount = -1;
+
+ if((tmpcs=fopen(filename, "rb"))==NULL)
+ {
+ strcpy(currentcf, empty_string);
+ return 1;
+ }
+ else
+ strcpy(currentcf, filename);
+
+ while(!feof(tmpcs))
+ {
+ configfilecount++;
+ fgets(tmpbuf, 8196, tmpcs);
+ configsys[configfilecount] = malloc(strlen(tmpbuf)+1);
+ strcpy(configsys[configfilecount], tmpbuf);
+ stripcrlf(configsys[configfilecount]);
+ }
+
+ fclose(tmpcs);
+ return 0;
+}
+
+/*
+ * Write the updated config file to disk and backup the original.
+ */
+int writeconfigfile(char *filename, char *backup)
+{
+ FILE *tmpcs;
+ int i;
+
+ if(backup)
+ {
+ remove(backup);
+ rename(filename, backup);
+ }
+ else
+ remove(filename);
+
+ if((tmpcs=fopen(filename, "wb"))==NULL)
+ return 1;
+
+ for(i=0;i<configfilecount;i++)
+ {
+ if(configsys[i])
+ {
+ fwrite(configsys[i], 1, strlen(configsys[i]), tmpcs);
+ /* Add the CRLF that got stripped in the reading stage. */
+ fwrite("\r\n", 1, 2, tmpcs);
+ free(configsys[i]);
+ }
+ }
+
+ fclose(tmpcs);
+ return 0;
+}
+/*
+ * Adds or replaces a SET variable based on the flags (CONFIG.SYS)
+ */
+void updateset(char *setname, char *newvalue, int flag)
+{
+ char *cmpbuf1, *cmpbuf2, *tmpptr, *tmpptr2, *nv;
+ int i, z, t;
+
+ nv=replaceem(newvalue);
+
+ cmpbuf1=malloc(strlen(setname)+2);
+ strcpy(cmpbuf1, setname);
+ strcat(cmpbuf1, "=");
+ for(i=0;i<configfilecount;i++)
+ {
+ if(strlen(cmpbuf1) <= strlen(configsys[i]))
+ {
+ tmpptr=(char *)strdup(configsys[i]);
+#if defined(__EMX__) || defined(__OS2__) || defined(WIN32) || defined(WINNT)
+ strupr(tmpptr);
+#endif
+ if((tmpptr2=(char*)strstr(tmpptr, "SET "))!=NULL)
+ {
+ tmpptr2 += 4;
+ cmpbuf2=malloc(strlen(tmpptr2)+1);
+ /* Remove any spaces from the string */
+ z=0;
+ for (t=0;t<strlen(tmpptr2) && z < strlen(cmpbuf1);t++)
+ {
+ if(tmpptr2[t] != ' ')
+ {
+ cmpbuf2[z]=tmpptr2[t];
+ z++;
+ }
+ }
+ cmpbuf2[z]=0;
+ if(stricmp(cmpbuf1, cmpbuf2) == 0)
+ {
+ /* Ok we found the entry, and if UPDATE_ALWAYS change it to the
+ new entry, otherwise exit */
+ if(flag == UPDATE_ALWAYS)
+ {
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFRemLine>,%s,%s\r\n", currentcf, configsys[i]);
+#endif
+ free(configsys[i]);
+ configsys[i] = malloc(strlen(setname)+strlen(nv)+6);
+ strcpy(configsys[i], "SET ");
+ strcat(configsys[i], setname);
+ strcat(configsys[i], "=");
+ strcat(configsys[i], nv);
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFAddLine>,%s,%s\r\n", currentcf, configsys[i]);
+#endif
+ free(cmpbuf1);free(cmpbuf2);free(tmpptr);
+ }
+ return;
+ }
+ free(cmpbuf2);
+ }
+ free(tmpptr);
+ }
+ }
+ /* Couldn't find the line so we'll add it */
+ configsys[configfilecount]=malloc(strlen(cmpbuf1)+strlen(nv)+6);
+ strcpy(configsys[configfilecount], "SET ");
+ strcat(configsys[configfilecount], setname);
+ strcat(configsys[configfilecount], "=");
+ strcat(configsys[configfilecount], nv);
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFAddLine>,%s,%s\r\n", currentcf, configsys[configfilecount]);
+#endif
+ configfilecount++;
+ free(cmpbuf1);
+}
+
+/*
+ * Adds an entry to a system variable (CONFIG.SYS)
+ */
+void updatesys(char *sysname, char *newvalue)
+{
+ char *cmpbuf1, *cmpbuf2, *tmpptr, *tmpptr2, *capbuf1, *capbuf2, *nv, *brian;
+ int i, z, t;
+
+ nv=replaceem(newvalue);
+
+ cmpbuf1=malloc(strlen(sysname)+2);
+ strcpy(cmpbuf1, sysname);
+ strcat(cmpbuf1, "=");
+ for(i=0;i<configfilecount;i++)
+ {
+ if(strlen(cmpbuf1) <= strlen(configsys[i]))
+ {
+ cmpbuf2=malloc(strlen(configsys[i])+1);
+ /* Remove any spaces from the string */
+ z=0;
+ for (t=0;t<strlen(configsys[i]) && z < strlen(cmpbuf1);t++)
+ {
+ if(configsys[i][t] != ' ')
+ {
+ cmpbuf2[z]=configsys[i][t];
+ z++;
+ }
+ }
+ cmpbuf2[z]=0;
+ if(stricmp(cmpbuf1, cmpbuf2) == 0)
+ {
+ /* Do a case insensitive comparison but preserve the case */
+ tmpptr = &configsys[i][t];
+ capbuf1=malloc(strlen(tmpptr)+1);
+ capbuf2=malloc(strlen(nv)+1);
+ strcpy(capbuf1, tmpptr);
+ strcpy(capbuf2, nv);
+#if defined(__EMX__) || defined(__OS2__) || defined(WINNT) || defined(WIN32)
+ strupr(capbuf1);
+ strupr(capbuf2);
+#endif
+ /* Ok, we found the line, and it doesn't have an entry so we'll add it */
+ if((tmpptr2=(char *)strstr(capbuf1, capbuf2)) == NULL)
+ {
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFRemLine>,%s,%s\r\n", currentcf, configsys[i]);
+#endif
+ brian = configsys[i];
+ configsys[i] = malloc(strlen(configsys[i])+strlen(nv)+4);
+ strcpy(configsys[i], brian);
+ free(brian);
+ /* Remove any trailing CRLFs */
+ if(configsys[i][strlen(configsys[i])-1]!=';')
+ strcat(configsys[i], ";");
+ strcat(configsys[i], nv);
+ strcat(configsys[i], ";");
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFAddLine>,%s,%s\r\n", currentcf, configsys[i]);
+#endif
+ }
+ free(cmpbuf1);free(cmpbuf2);free(capbuf1);free(capbuf2);
+ return;
+ }
+ free(cmpbuf2);
+ }
+ }
+ /* Couldn't find the line so we'll add it */
+ configsys[configfilecount]=malloc(strlen(cmpbuf1)+strlen(nv)+3);
+ strcpy(configsys[configfilecount], cmpbuf1);
+ strcat(configsys[configfilecount], nv);
+ strcat(configsys[configfilecount], ";");
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFAddLine>,%s,%s", currentcf, configsys[configfilecount]);
+#endif
+ configfilecount++;
+ free(cmpbuf1);
+ if(nv)
+ free(nv);
+}
+
+/*
+ * Removes a line from a config file.
+ */
+void removeline(char *text)
+{
+ int z;
+ for(z=0;z<configfilecount;z++)
+ {
+ if(stricmp(configsys[z], text) == 0)
+ {
+ int t;
+
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFRemLine>,%s,%s\r\n", currentcf, configsys[z]);
+#endif
+ free(configsys[z]);
+ for(t=z;t<(configfilecount-1);t++)
+ configsys[t] = configsys[t+1];
+ configfilecount--;
+ }
+ }
+}
+
+
+/*
+ * The Window peocedure for the confirmation dialog.
+ */
+#if 0
+MRESULT EXPENTRY ConfirmDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+ SWP winpos;
+
+ switch (msg)
+ {
+ case WM_INITDLG:
+ WinSetWindowText(hWnd, INSTALLER_TITLE);
+ WinEnableWindow(WinWindowFromID(mainhwnd, I_Cancel), FALSE);
+ WinSetDlgItemText(hWnd, I_Confirm, confirmstring);
+ WinQueryWindowPos(mainhwnd, &winpos);
+ WinSetWindowPos(hWnd, HWND_TOP, winpos.x+30, winpos.y+30, 0, 0, SWP_MOVE | SWP_ZORDER);
+ break;
+ case WM_COMMAND:
+ WinEnableWindow(WinWindowFromID(mainhwnd, I_Cancel), TRUE);
+ switch ( SHORT1FROMMP(mp1) )
+ {
+ case I_Ja:
+ WinDismissDlg(hWnd, 0);
+ break;
+ case I_Alle:
+ WinDismissDlg(hWnd, 1);
+ break;
+ case I_Nein:
+ WinDismissDlg(hWnd, 2);
+ break;
+ case I_Halt:
+ success=2;
+ installstate=ABORTED;
+ WinDismissDlg(hWnd, 3);
+ break;
+ }
+ break;
+ default :
+ return(WinDefDlgProc(hWnd, msg, mp1, mp2));
+ }
+ return(0L);
+}
+#endif
+/*
+ * Display a confirmation dialog with the options: YES NO ALL CANCEL
+ * Returns: 0 for YES, 1 for ALL, 2 for NO and 3 for CANCEL
+ */
+int confirm(char *format, ...) {
+ va_list args;
+
+ /* if no confirmation, return 1, meaning overwrite all */
+ if (stricmp(INSTALLER_CONFIRM_OVERWRITE, "no") == 0)
+ return 1;
+
+ va_start(args, format);
+ vsprintf(confirmstring, format, args);
+ va_end(args);
+
+ /* Do something here in wxwindows */
+ return 1;
+}
+
+/*
+ * A function to grab a file from an embedded archive and extract it to the TEMP directory.
+ */
+void grabfile(char *filename)
+{
+ no_update = 1;
+ settempdir();
+ remove(filename);
+ aceseek_entry(0);
+ resetglobals();
+ installer_unpack(filename, 2);
+ no_update = 0;
+}
+
+/*
+ * This thread runs along side the main thread allowing the user to cancel the process.
+ */
+void install_thread(void *param)
+{
+ char tmpinstallpath[1024];
+ int k, j, installcount=0, installed=0;
+
+ if(INSTALLER_PACKAGE_COUNT == 2)
+ packagesselected[1] = TRUE;
+
+ installstate = INSTALLING;
+
+#ifdef ENABLE_LOGGING
+ if((logfile=fopen(instlog, "ab"))==NULL)
+ {
+ error("Log file \"%s\" open failed! Installation aborted!", instlog);
+ exit(1);
+ }
+
+ fprintf(logfile, "[%s]\r\n<Version>,%s\r\n<Start>\r\n", INSTALLER_APPLICATION, INSTALLER_VERSION);
+#endif
+
+ /* Create nested subdirectories if necessary. */
+ strcpy(tmpinstallpath, installdir);
+ for(k=3;k<strlen(installdir);k++)
+ {
+ if(tmpinstallpath[k] == '\\')
+ {
+ tmpinstallpath[k] = 0;
+#if defined(__EMX__) || defined(__CYGWIN__) || defined(UNIX)
+ if (!mkdir(tmpinstallpath, 0))
+#else
+ if (!mkdir(tmpinstallpath))
+#endif
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<NewDir>,%s\r\n", tmpinstallpath);
+#else
+ ;
+#endif
+ tmpinstallpath[k] = '\\';
+ }
+ }
+
+#if defined(__EMX__) || defined(__CYGWIN__) || defined(UNIX)
+ if (!mkdir(installdir, 0))
+#else
+ if (!mkdir(installdir))
+#endif
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<NewDir>,%s\r\n", installdir);
+#else
+ ;
+#endif
+
+ /*if(strlen(installdir) > 0 && installdir[0] > 'a'-1 && installdir[0] < 'z'+1)
+ installdir[0]=installdir[0] - ('a'-'A');
+ if(strlen(installdir)>2 && installdir[1]==':' && installdir[2]=='\\')
+ DosSetDefaultDisk((int)(installdir[0]-'A'+1));*/
+
+ setdrivedir(installdir);
+
+ /* Unpack files to destination directory */
+ for(j=1;j<INSTALLER_PACKAGE_COUNT;j++)
+ {
+ if(packagesselected[j] == TRUE)
+ installcount++;
+ }
+ if(installcount == 0)
+ {
+ mesg("No packages selected for installation!");
+ }
+ else
+ {
+ for(j=1;j<INSTALLER_PACKAGE_COUNT;j++)
+ {
+ if(packagesselected[j] == TRUE)
+ {
+#if 0
+ char statustext[512];
+#endif
+ aceseek_entry(j);
+ resetglobals();
+#if 0
+ sprintf(statustext,"Copying Files for %s %d/%d, Press \"Exit Installation\" to Abort.", INSTALLER_PACKAGES[j], installed+1, installcount);
+ WinSetDlgItemText(mainhwnd, I_Info3, statustext);
+#endif
+ /* filename parameter when null is all files */
+ installer_unpack(NULL, 2);
+ installed++;
+ }
+ }
+ }
+
+ if(success==1)
+ {
+ error("Error unpacking files, Installer may be corrupt!");
+ }
+
+ if(success==2)
+ {
+ error("User aborted installation!");
+ }
+
+ if(installstate != ABORTED)
+ installstate = COMPLETED;
+
+#if 0
+ sendmessage(0, 2);
+#endif
+}
+
+/*
+ * Use the information from the .cfg file which is embedded in the EXE to update the
+ * CONFIG.SYS settings.
+ */
+void configsys_update(void)
+{
+ char *arg1, *arg2, *arg3;
+ char temp[5000];
+ int z, argn=0;
+
+ if(readconfigfile(csfile))
+ return;
+
+ /* Update Miscellaneous lines */
+ if(strlen(INSTALLER_SYSLINE)>0)
+ {
+ char *tmpptr = &temp[0];
+ int len;
+
+ strcpy(temp, INSTALLER_SYSLINE);
+ temp[4999] = 0;
+ len = strlen(temp);
+
+ for(z=0;z<len;z++)
+ {
+ if(temp[z]==',')
+ {
+ char *tmpptr2;
+
+ temp[z] = 0;
+ tmpptr2 = replaceem(tmpptr);
+ tmpptr = &temp[z+1];
+ removeline(tmpptr2);
+ configsys[configfilecount] = tmpptr2;
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFAddLine>,%s,%s\r\n", currentcf, tmpptr2);
+#endif
+ configfilecount++;
+ }
+ }
+ if(tmpptr && *tmpptr)
+ {
+ char *tmpptr2;
+
+ tmpptr2 = replaceem(tmpptr);
+ removeline(tmpptr2);
+ configsys[configfilecount] = tmpptr2;
+#ifdef ENABLE_LOGGING
+ fprintf(logfile, "<CFAddLine>,%s,%s\r\n", currentcf, tmpptr2);
+#endif
+ configfilecount++;
+ }
+
+ }
+ /* Update SET variables */
+ if(strlen(INSTALLER_SETS)>0)
+ {
+ strcpy(temp, INSTALLER_SETS);
+ argn=0;
+ arg1=&temp[0];
+ arg2=arg3=NULL;
+ for(z=0;z<strlen(INSTALLER_SETS);z++)
+ {
+ if(temp[z]==',')
+ {
+ argn++;
+ temp[z]=0;
+ switch(argn)
+ {
+ case 1:
+ arg2=&temp[z+1];
+ break;
+ case 2:
+ arg3=&temp[z+1];
+ break;
+ case 3:
+ argn=0;
+ updateset(arg1, arg2, (int)(arg3[0]-'0'));
+ arg1=&temp[z+1];
+ arg2=arg3=NULL;
+ break;
+ }
+ }
+ }
+ if(arg3)
+ updateset(arg1, arg2, (int)arg3-'0');
+ }
+ /* Update system variables */
+ if(strlen(INSTALLER_SYSVAR)>0)
+ {
+ strcpy(temp, INSTALLER_SYSVAR);
+ argn=0;
+ arg1=&temp[0];
+ arg2=NULL;
+ for(z=0;z<strlen(INSTALLER_SYSVAR);z++)
+ {
+ if(temp[z]==',')
+ {
+ argn++;
+ temp[z]=0;
+ switch(argn)
+ {
+ case 1:
+ arg2=&temp[z+1];
+ break;
+ case 2:
+ argn=0;
+ updatesys(arg1, arg2);
+ arg1=&temp[z+1];
+ arg2=NULL;
+ break;
+ }
+ }
+ }
+ if(arg2)
+ updatesys(arg1, arg2);
+ }
+
+ writeconfigfile(csfile, bufile);
+}
+
+/*
+ * Reads a line from a file and returns it in raw.
+ */
+void getline(FILE *f, char *raw)
+{
+ memset(raw, 0, 256);
+ fgets(raw, 255, f);
+ stripcrlf(raw);
+}
+
+/*
+ * Removes a character from a buffer by advancing the buffer to the left.
+ */
+void removechar(char *buffer, int thisone, int len)
+{
+ int x;
+
+ for(x=thisone;x<len;x++)
+ buffer[x] = buffer[x+1];
+}
+
+/*
+ * Breaks up a line in raw into it's components.
+ */
+void parseline(char *raw, char comment, char delimiter, char quotes, char *entry, char *entrydata, char *entrydata2)
+{
+ char in[256];
+ int z, len, in_quotes = 0, entrynum=0, last = 0;
+
+ strcpy(entry, empty_string);
+ strcpy(entrydata, empty_string);
+ strcpy(entrydata2, empty_string);
+ strcpy(in, raw);
+
+ if(in[strlen(in)-1] == '\n')
+ in[strlen(in)-1] = 0;
+
+ if(in[0] != comment)
+ {
+ len=strlen(in);
+ for(z=0;z<len;z++)
+ {
+ if(!in_quotes && in[z] == delimiter)
+ {
+ in[z] = 0;
+ /* Strip any other delimiters */
+ z++;
+ while(in[z] == delimiter && z < len)
+ z++;
+ if(!entrynum)
+ strcpy(entry, in);
+ else
+ {
+ strcpy(entrydata, &in[last]);
+ strcpy(entrydata2, &in[z]);
+ }
+ last = z;
+ if(entrynum)
+ return;
+ entrynum++;
+ }
+ if(in[z] == quotes)
+ {
+ removechar(in, z, len);
+ z--;
+ len--;
+ if(in_quotes)
+ in_quotes = 0;
+ else
+ in_quotes = 1;
+ }
+ }
+ if(!entrynum)
+ strcpy(entry, in);
+ else
+ strcpy(entrydata, &in[last]);
+ }
+}
+
+/*
+ * Reads a line from the file and splits it up into it's components.
+ */
+int getparseline(FILE *f, char comment, char delimiter, char quotes, char *raw, char *entry, char *entrydata, char *entrydata2)
+{
+ getline(f, raw);
+ parseline(raw, comment, delimiter, quotes, entry, entrydata, entrydata2);
+ return strlen(raw);
+}
+
+
+void install_init(char *installername)
+{
+ if((self = fopen(installername, "rb")) == NULL)
+ {
+ mesg("Could not open SFX archive for reading!");
+ exit(1);
+ }
+ if(loadheader() == FALSE)
+ {
+ mesg("Could not load all required variables!");
+ exit(3);
+ }
+
+ strcpy(installdir, INSTALLER_PATH);
+}
+
+