From: tomo Date: Mon, 13 Aug 2001 11:49:02 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'XEmacs-21_4'. X-Git-Tag: r21-2-39~2 X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=commitdiff_plain;h=87535ceaf7fcb2d0684688e0c204e1229b5cbcbe;hp=14144012929ab5944f367d5d1b323ab8268abb05 This commit was manufactured by cvs2svn to create branch 'XEmacs-21_4'. --- diff --git a/netinstall/ChangeLog b/netinstall/ChangeLog new file mode 100644 index 0000000..8e2dad2 --- /dev/null +++ b/netinstall/ChangeLog @@ -0,0 +1,128 @@ +2000-12-31 Martin Buchholz + + * XEmacs 21.2.39 is released. + +2000-12-28 Andy Piper + + * desktop.cc (FROB): add more app paths. + +2000-12-24 Fabrice Popineau + + * choose.cc (create_listview): CreateWindowEx() does not take this kind of + parameter. + + * choose.cc (package_sort): + * hash.cc (rev_len): + * site.cc (site_sort): must be __cdecl to be called by qsort(). + + * download.cc: + * install.cc: + * nio-file.cc: + * tar.cc: because of the redefinition of stat to _stat, the + inclusion of win32 headers has to be delayed. + + * win32.h: added some declarations, such as CDECL if + not defined, #define for functions that are not standard in msvc + libc (strdup, stat ...) + + * concat.h, concat.cc (concat): must be declared CDECL + + * desktop.cc: is needed. + + * dialog.h (NEXT): cast needed, the first parameter of EndDialog() must + be a HWND. + + * diskfull.cc: syntax when declaring GDFS. + + * ini.cc: Various `extern "C"' declarations: yylineno, yyerror() + and fprintf(). Various CDECL declarations: yyerror(), fprintf(). + + * inilex.l: required. + + * iniparse.y: use strdup(), require "win32.h" and + + * install.cc (dialog): syntax when declaring. CreateDialog() + returns a HWND. + + * postinstall.cc: and are needed. + + * regedit.cc (find_cygwin_mount): WIN32_NATIVE does not know + anything about Cygwin stuff. + + * setup.mak: new makefile for WIN32_NATIVE. + + * splash.cc (load_dialog): GetDlgItem() returns a HWND. + + * tar.cc: msvc knows about __int64, but not `long long'. + + * win32.h: is missing for regedit.cc. Also, I ended up + in including because the files listed there are not + enough for . + + * desktop.cc: + * fromcwd.cc: + * install.cc: + * postinstall.cc: does not exist for WIN32_NATIVE + + * choose.cc (do_choose): + * ini.cc (do_ini): + * nio-ftp.cc (ftp_line): the construct (x ?: y) is not standard. + +2000-12-24 Andy Piper + + * choose.cc (read_installed_db): grok package versions correctly. + + * Makefile.in.in: add MINGW define. + +2000-12-18 Andy Piper + + * res.rc: better look and feel. + +2000-12-18 Andy Piper + + * desktop.cc (do_desktop_setup): more app path fiddling. + +2000-12-13 Andy Piper + + * root.cc (dialog_cmd): create the root in the registry if we are successful. + + * desktop.cc (find_xemacs_exe_path): new function. Split out from + find_xemacs_exe (). + (find_xemacs_exe_name): ditto. + (do_desktop_setup): setup app paths if we are installing xemacs + itself. + (do_desktop): use new functions. + + * regedit.cc (create_xemacs_root): fix key name. + (find_xemacs_root): set isnative whatever the key value. + (set_app_path): new function. Set path for an app. + +2000-12-12 Andy Piper + + * package-net.el (package-net-convert-index-to-ini): use sensible defaults. + +2000-12-12 Andy Piper + + * reginfo.h: new macros. + + * iniparse.y: define xemacs_package. + + * ini.h: declare xemacs_package. + + * fromcwd.cc (found_file): guess core type from name. + + * concat.cc: kill warnings. + * net.cc: ditto. + + * choose.cc (do_choose): pick up core package type chosen. + + * Makefile.in.in: make sure we can pick up a mingw zlib. + + * desktop.cc: fix desktop icon creation. + +2000-11-12 Andy Piper + + * all: port from cygwin setup. + +%%% $Id: ChangeLog,v 1.1.2.4 2000/12/30 10:01:41 andyp Exp $ +$Revision: 1.1.2.4 $ diff --git a/netinstall/Makefile.in.in b/netinstall/Makefile.in.in new file mode 100644 index 0000000..59dfb83 --- /dev/null +++ b/netinstall/Makefile.in.in @@ -0,0 +1,252 @@ +## Copyright (c) 2000, Red Hat, Inc. +## +## 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. +## +## A copy of the GNU General Public License can be found at +## http://www.gnu.org/ +## +## Written by Christopher Faylor +## Adapted for XEmacs by Andy Piper +## +## Makefile for Cygwin installer + +## FIXME: integrate autoload.c so that wininet doesn't have to be linked. + +## For performance and consistency, no built-in rules +.SUFFIXES: +.SUFFIXES: .c .cc .h .o +## ==================== Things "configure" will edit ==================== + +@SET_MAKE@ +SHELL = /bin/sh +RM = rm -f +pwd = /bin/pwd + +CC=@CC@ +CPP=@CPP@ +CFLAGS=@CFLAGS@ +CPPFLAGS=@CPPFLAGS@ +LDFLAGS=@LDFLAGS@ +ALLOCA=@ALLOCA@ +LN_S=@LN_S@ +version=@version@ + +## This will be the name of the generated binary and is set automatically +## by configure. +PROGNAME=@PROGNAME@ +INSTALLABLES=setup +#ifdef USE_GNU_MAKE +vpath %.c @srcdir@ +vpath %.cc @srcdir@ +vpath %.h @srcdir@ +#else +VPATH=@srcdir@ +#endif + +## ==================== Where To Install Things ==================== + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +srcdir=@srcdir@ +datadir=@datadir@ +instvardir=@instvardir@ +top_srcdir=@top_srcdir@ +archlibdir=@archlibdir@ +configuration=@configuration@ +moduledir=@moduledir@ +sitemoduledir=@sitemoduledir@ + +## ==================== Utility Programs for the Build ================= + +INSTALL = @install_pp@ @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +SHELL = @SHELL@ +## ========================== Lists of Files =========================== + +#define NO_SHORTNAMES +#define NOT_C_CODE +#include "../src/config.h" + +program_transform_name = @program_transform_name@ + +CC = @CC@ +CC_FOR_TARGET = $(CC) + +LOCALCFLAGS = $(CFLAGS) -DMINGW +CXXFLAGS = $(LOCALCFLAGS) -fno-exceptions -nostdinc++ -fno-rtti + +WINDRES = windres +MINGW_INCLUDES = -I. -I$(srcdir) +MINGW_CXXFLAGS = $(CXXFLAGS) -mno-cygwin $(MINGW_INCLUDES) -mwindows +MINGW_CFLAGS = $(LOCALCFLAGS) -mno-cygwin $(MINGW_INCLUDES) -mwindows +MINGW_ZLIB_DIR = /usr/local/lib + +PROGS = setup.exe + +CONFIG_H = ../src/config.h + +OBJS = \ + choose.o \ + concat.o \ + desktop.o \ + dialog.o \ + diskfull.o \ + download.o \ + find.o \ + fromcwd.o \ + geturl.o \ + hash.o \ + ini.o \ + inilex.o \ + iniparse.o \ + install.o \ + localdir.o \ + log.o \ + main.o \ + mkdir.o \ + mklink2.o \ + regedit.o \ + msg.o \ + net.o \ + netio.o \ + nio-ie5.o \ + nio-file.o \ + nio-ftp.o \ + nio-http.o \ + other.o \ + postinstall.o \ + res.o \ + root.o \ + simpsock.o \ + site.o \ + source.o \ + splash.o \ + state.o \ + tar.o \ + version.o + +.SUFFIXES: +.NOEXPORT: + +.PHONY: all install + +all: Makefile $(PROGS) + +setup.exe: $(OBJS) + $(CXX) $(MINGW_CXXFLAGS) -o $@ $(OBJS) \ + -lole32 -lwsock32 -lnetapi32 -ladvapi32 \ + -luuid -lkernel32 -luser32 -lwininet \ + -L$(MINGW_ZLIB_DIR) -lz -lmingw32 + @chmod a-x $@ + +install: + @echo; echo "Installing net setup." + for file in ${INSTALLABLES} ; do \ + (cd .. && $(INSTALL_PROGRAM) netinstall/$${file} ${bindir}/$${file}) ; \ + done + +version.c : $(srcdir)/ChangeLog Makefile + V=`grep '^\$$Revision.*' $(srcdir)/ChangeLog \ + | sed -e 's/\$$Revision:* *//' \ + -e 's/ *$$.*//'` ;\ + echo "char *version = \"$$V\";" > version.tmp ;\ + echo "static char *id = \"\\n%%% setup-version $$V\\n\";" >> version.tmp + mv version.tmp version.c + +%.o: %.rc + $(WINDRES) --include-dir $(srcdir) -o $@ $< + +%.o: %.c + $(CC) $(MINGW_CFLAGS) -c -o $@ ${srcdir}/$< + +%.o: %.cc + $(CC) $(MINGW_CXXFLAGS) -c -o $@ ${srcdir}/$< + +iniparse.c iniparse.h : iniparse.y + bison -d -o iniparse.c $(srcdir)/iniparse.y + +inilex.c : inilex.l iniparse.h + flex -8 $(srcdir)/inilex.l + mv lex.yy.c inilex.c + +.PHONY: mostlyclean clean distclean realclean extraclean + +mostlyclean: + $(RM) *.o *.i core $(PROGS) + +clean: mostlyclean + +distclean: clean + $(RM) GNUmakefile Makefile Makefile.in TAGS + +realclean: distclean + +extraclean: distclean + $(RM) *~ \#* + +choose.o: choose.cc win32.h dialog.h resource.h state.h ini.h concat.h \ + msg.h log.h find.h reginfo.h +concat.o: concat.cc +desktop.o: desktop.cc win32.h resource.h ini.h msg.h state.h concat.h \ + mkdir.h dialog.h version.h port.h +dialog.o: dialog.cc win32.h dialog.h msg.h log.h +diskfull.o: diskfull.cc win32.h diskfull.h +download.o: download.cc win32.h resource.h msg.h ini.h dialog.h \ + concat.h geturl.h state.h mkdir.h log.h +find.o: find.cc win32.h port.h +fromcwd.o: fromcwd.cc win32.h ini.h resource.h concat.h state.h \ + dialog.h msg.h find.h version.h port.h +geturl.o: geturl.cc win32.h dialog.h \ + geturl.h resource.h netio.h msg.h log.h +hash.o: hash.cc hash.h +ini.o: ini.cc win32.h ini.h resource.h concat.h state.h geturl.h \ + dialog.h msg.h mkdir.h log.h reginfo.h version.h +inilex.o: inilex.c win32.h \ + ini.h \ + iniparse.h +iniparse.o: iniparse.c ini.h \ + iniparse.h \ + port.h +install.o: install.cc win32.h \ + resource.h ini.h dialog.h concat.h geturl.h mkdir.h state.h tar.h \ + diskfull.h msg.h regedit.h reginfo.h log.h hash.h port.h +localdir.o: localdir.cc win32.h dialog.h resource.h state.h msg.h \ + concat.h log.h +log.o: log.cc win32.h resource.h msg.h log.h dialog.h state.h concat.h \ + mkdir.h +main.o: main.cc win32.h resource.h dialog.h state.h msg.h netio.h \ + find.h log.h port.h +mkdir.o: mkdir.cc win32.h mkdir.h +mklink2.o: mklink2.c win32.h /usr/include/w32api/shlobj.h +msg.o: msg.cc win32.h dialog.h log.h +net.o: net.cc win32.h dialog.h resource.h state.h msg.h log.h +netio.o: netio.cc win32.h resource.h state.h msg.h netio.h nio-file.h \ + nio-ie5.h nio-http.h nio-ftp.h dialog.h log.h port.h +nio-file.o: nio-file.cc win32.h netio.h nio-file.h resource.h msg.h +nio-ftp.o: nio-ftp.cc win32.h resource.h state.h simpsock.h log.h \ + netio.h nio-ftp.h +nio-http.o: nio-http.cc win32.h resource.h state.h simpsock.h msg.h \ + netio.h nio-http.h +nio-ie5.o: nio-ie5.cc win32.h resource.h state.h dialog.h msg.h \ + netio.h nio-ie5.h +other.o: other.cc win32.h dialog.h resource.h state.h msg.h log.h +postinstall.o: postinstall.cc win32.h state.h dialog.h find.h concat.h \ + port.h +regedit.o: regedit.cc win32.h reginfo.h regedit.h msg.h resource.h \ + dialog.h +root.o: root.cc win32.h dialog.h resource.h state.h msg.h regedit.h \ + reginfo.h concat.h log.h +simpsock.o: simpsock.cc win32.h simpsock.h msg.h +site.o: site.cc win32.h dialog.h resource.h state.h geturl.h msg.h \ + concat.h regedit.h reginfo.h log.h port.h +source.o: source.cc win32.h dialog.h resource.h state.h msg.h log.h +splash.o: splash.cc win32.h dialog.h resource.h msg.h version.h +state.o: state.cc state.h +tar.o: tar.cc win32.h tar.h mkdir.h log.h port.h +version.o: version.c diff --git a/netinstall/README b/netinstall/README new file mode 100644 index 0000000..21d1877 --- /dev/null +++ b/netinstall/README @@ -0,0 +1,25 @@ +This directory contains the source for the setup program for the cygwin +net releases. + + + +To-Do list: + +ini.cc: add field in setup.ini to specify whether package is installed +by default, or not. + +install.cc: scan newly installed files for README files, show list to +user, let them read them if they want. + +download.cc: add a "total progress" indicator, like the install one. + +add a "category" field to setup.ini, let user choose which categories +of packages to install, perhaps with a "custom..." button to lead to +the current chooser. + +remember which packages were selected to be skipped, and which prev/curr/exp +option was last selected, and recall them each time the chooser runs. + +Add friendly error reporting to simpsock.cc + +Add option to download sources also. diff --git a/netinstall/README.xemacs b/netinstall/README.xemacs new file mode 100644 index 0000000..f962e65 --- /dev/null +++ b/netinstall/README.xemacs @@ -0,0 +1,23 @@ +This directory contains the source for the setup program for the +XEmacs net releases. + +This code has been adapted from the cygwin net release installer. In +particular note that the cygwin net release installer is actively +maintained and therefore we will want to incorporate improvements from +that. I have therefore tried to use the cygwin way wherever +possible. I have however cleaned up the code somewhat so that there +are not billions of warnings. + +This program should get built as part of the standard XEmacs +make. Note however that if you use trhe cygwin build you will need a +NON CYGWIN VERSION OF ZLIB. + +New files: + regedit.cc: + regedit.h + reginfo.h + Makefile.in.in: + +Deleted files: + mount.cc: moved to regedit.cc + mount.h: moved to regedit.h diff --git a/netinstall/autoload.c b/netinstall/autoload.c new file mode 100644 index 0000000..6fae77c --- /dev/null +++ b/netinstall/autoload.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +#include "win32.h" + +typedef struct { + char *name; + HINSTANCE handle; +} DllInfo; + +#define DLL(n) static DllInfo n ## _info __asm__ (#n "_info") = { #n, 0} + +#define Auto(dll, func, size) \ + __asm__ ("\t.data"); \ + __asm__ ("\t.global\t_" #func "@" #size); \ + __asm__ ("_" #func "@" #size ":"); \ + __asm__ ("\tcall\tautoload_common"); \ + __asm__ ("\t.long\t" #dll "_info"); \ + __asm__ ("\t.ascii\t\"" #func "\\0\"") + +DLL (wininet); + +Auto (wininet, InternetAttemptConnect, 4); +Auto (wininet, InternetCloseHandle, 4); +Auto (wininet, InternetGetLastResponseInfoA, 12); +Auto (wininet, InternetOpenA, 20); +Auto (wininet, InternetOpenUrlA, 24); +Auto (wininet, InternetReadFile, 16); +Auto (wininet, InternetSetOptionA, 16); +Auto (wininet, InternetQueryOptionA, 16); +Auto (wininet, HttpQueryInfoA, 20); +Auto (wininet, HttpSendRequestA, 20); + +typedef struct { + DllInfo *dll; + char name[100]; +} AutoEntry; + +static void autoload_common () __asm__ ("autoload_common"); + +static void +autoload_common (int x) +{ + int fp, rel; + unsigned char *proc; + HINSTANCE h; + AutoEntry *a; + + a = *(AutoEntry **)(&x - 1); + if (a->dll->handle == 0) + { + h = LoadLibrary (a->dll->name); + a->dll->handle = h; + } + fp = (int) GetProcAddress (a->dll->handle, a->name); + proc = ((unsigned char *)a) - 5; + rel = fp - (int)(a); /* now it's a relative call */ + *proc++ = 0xe9; /* jump near 32-bit relative */ + *proc++ = rel; + *proc++ = rel>>8; + *proc++ = rel>>16; + *proc++ = rel>>24; + + *(int *)(&x-1) = (int)proc-5; +} diff --git a/netinstall/check-na.bmp b/netinstall/check-na.bmp new file mode 100644 index 0000000..c139e54 Binary files /dev/null and b/netinstall/check-na.bmp differ diff --git a/netinstall/check-no.bmp b/netinstall/check-no.bmp new file mode 100644 index 0000000..3639605 Binary files /dev/null and b/netinstall/check-no.bmp differ diff --git a/netinstall/check-yes.bmp b/netinstall/check-yes.bmp new file mode 100644 index 0000000..f328dc2 Binary files /dev/null and b/netinstall/check-yes.bmp differ diff --git a/netinstall/choose-rtarrow.bmp b/netinstall/choose-rtarrow.bmp new file mode 100644 index 0000000..5f719e1 Binary files /dev/null and b/netinstall/choose-rtarrow.bmp differ diff --git a/netinstall/choose-spin.bmp b/netinstall/choose-spin.bmp new file mode 100644 index 0000000..8779f6d Binary files /dev/null and b/netinstall/choose-spin.bmp differ diff --git a/netinstall/choose.cc b/netinstall/choose.cc new file mode 100644 index 0000000..40d4bc8 --- /dev/null +++ b/netinstall/choose.cc @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to let the user choose which packages + to install, and which versions of the package when more than one + version is provided. The "trust" level serves as an indication as + to which version should be the default choice. At the moment, all + we do is compare with previously installed packages to skip any + that are already installed (by setting the action to ACTION_SAME). + While the "trust" stuff is supported, it's not really implemented + yet. We always prefer the "current" option. In the future, this + file might have a user dialog added to let the user choose to not + install packages, or to install packages that aren't installed by + default. */ + +#include "win32.h" +#include +#include +#include + +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "ini.h" +#include "concat.h" +#include "msg.h" +#include "log.h" +#include "find.h" +#include "reginfo.h" + +#define HMARGIN 10 +#define ROW_MARGIN 5 +#define ICON_MARGIN 4 + +#define CHECK_SIZE 11 + +#define TRUST_KEEP 101 +#define TRUST_UNINSTALL 102 +#define TRUST_NONE 103 + +static int initialized = 0; + +static int full_list = 0; + +static int scroll_ulc_x, scroll_ulc_y; + +static HWND lv, nextbutton; +static TEXTMETRIC tm; +static int header_height; +static HANDLE sysfont; +static int row_height; +static HANDLE bm_spin, bm_rtarrow, bm_checkyes, bm_checkno, bm_checkna; +static HDC bitmap_dc; + +static struct { + char *text; + int slen; + int width; + int x; +} headers[] = { + { "Current", 7, 0, 0 }, +#define CURRENT_COL 0 + { "New", 3, 0, 0 }, +#define NEW_COL 1 + { "Src?", 4, 0, 0 }, +#define SRC_COL 2 + { "Package", 7, 0, 0 }, +#define PACKAGE_COL 3 + { 0, 0, 0, 0 } +}; +#define NUM_COLUMNS (sizeof(headers)/(sizeof(headers[0]))-1) + +int *package_indexes, nindexes; + +struct ExtraPackageInfo { + char *installed_file; /* filename of previous "install" file */ + char *installed_ver; /* version part */ + int installed_size; /* ditto, size. */ + + int in_partial_list; + int pick; + int npick; + int which_is_installed; /* == TRUST* or -1 */ + + struct { + int src_avail; + int trust; /* may be keep or uninstall */ + char *caption; /* ==0 at EOL */ + } chooser[NTRUST+3]; /* one extra for NULL above */ +}; + +static ExtraPackageInfo *extra; + +static void +paint (HWND hwnd) +{ + HDC hdc; + PAINTSTRUCT ps; + int x, y, i, ii; + + hdc = BeginPaint (hwnd, &ps); + + SelectObject (hdc, sysfont); + + RECT cr; + GetClientRect (hwnd, &cr); + + POINT p; + + x = cr.left - scroll_ulc_x; + y = cr.top - scroll_ulc_y + header_height; + + + for (i=0; headers[i].text; i++) + { + TextOut (hdc, x+headers[i].x, 3, headers[i].text, headers[i].slen); + MoveToEx (hdc, x+headers[i].x, header_height-3, &p); + LineTo (hdc, x+headers[i].x+headers[i].width, header_height-3); + } + + IntersectClipRect (hdc, cr.left, cr.top+header_height, cr.right, cr.bottom); + + for (ii=0; ii 1) + { + SelectObject (bitmap_dc, bm_spin); + BitBlt (hdc, x+headers[NEW_COL].x, by, 11, 11, + bitmap_dc, 0, 0, SRCCOPY); + } + } + + HANDLE check_bm = bm_checkna; + if (extra[i].chooser[extra[i].pick].src_avail) + { + if (package[i].srcaction == SRCACTION_NO) + check_bm = bm_checkno; + else if (package[i].srcaction == SRCACTION_YES) + check_bm = bm_checkyes; + } + SelectObject (bitmap_dc, check_bm); + BitBlt (hdc, x+headers[SRC_COL].x, by, 11, 11, + bitmap_dc, 0, 0, SRCCOPY); + + if (package[i].name) + TextOut (hdc, x+headers[PACKAGE_COL].x, r, package[i].name, strlen(package[i].name)); + } + + if (nindexes == 0) + { + static char *m = "Nothing to Install/Update"; + TextOut (hdc, HMARGIN, header_height, m, strlen (m)); + } + + EndPaint (hwnd, &ps); +} + +static void +scroll_common (HWND hwnd, int which, int *var, int code) +{ + SCROLLINFO si; + si.cbSize = sizeof (si); + si.fMask = SIF_ALL; + GetScrollInfo (hwnd, which, &si); + + switch (code) + { + case SB_THUMBTRACK: + si.nPos = si.nTrackPos; + break; + case SB_THUMBPOSITION: + break; + case SB_BOTTOM: + si.nPos = si.nMax; + break; + case SB_TOP: + si.nPos = 0; + break; + case SB_LINEDOWN: + si.nPos += row_height; + break; + case SB_LINEUP: + si.nPos -= row_height; + break; + case SB_PAGEDOWN: + si.nPos += si.nPage * 9/10; + break; + case SB_PAGEUP: + si.nPos -= si.nPage * 9/10; + break; + } + + if ((int)si.nPos < 0) + si.nPos = 0; + if ((int)(si.nPos + si.nPage) > si.nMax) + si.nPos = si.nMax - si.nPage; + + si.fMask = SIF_POS; + SetScrollInfo (hwnd, which, &si, TRUE); + + int ox = scroll_ulc_x; + int oy = scroll_ulc_y; + *var = si.nPos; + + RECT cr, sr; + GetClientRect (hwnd, &cr); + sr = cr; + sr.top += header_height; + ScrollWindow (hwnd, ox - scroll_ulc_x, oy - scroll_ulc_y, &sr, &sr); + sr.bottom = sr.top; + sr.top = cr.top; + ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr); +} + +static LRESULT CALLBACK +list_vscroll (HWND hwnd, HWND hctl, UINT code, int pos) +{ + scroll_common (hwnd, SB_VERT, &scroll_ulc_y, code); + return FALSE; +} + +static LRESULT CALLBACK +list_hscroll (HWND hwnd, HWND hctl, UINT code, int pos) +{ + scroll_common (hwnd, SB_HORZ, &scroll_ulc_x, code); + return FALSE; +} + +static LRESULT CALLBACK +list_click (HWND hwnd, BOOL dblclk, int x, int y, UINT hitCode) +{ + int r; + + if (nindexes == 0) + return 0; + + if (y < header_height) + return 0; + x += scroll_ulc_x; + y += scroll_ulc_y - header_height; + + r = (y + ROW_MARGIN/2) / row_height; + + if (r < 0 || r >= npackages) + return 0; + + int p = package_indexes[r]; + + if (x >= headers[NEW_COL].x - HMARGIN/2 && x <= headers[NEW_COL+1].x - HMARGIN/2) + { + extra[p].pick ++; + if (extra[p].chooser[extra[p].pick].caption == 0) + extra[p].pick = 0; + } + + if (x >= headers[SRC_COL].x - HMARGIN/2 && x <= headers[SRC_COL+1].x - HMARGIN/2) + { + if (extra[p].chooser[extra[p].pick].src_avail) + package[p].srcaction ^= (SRCACTION_NO^SRCACTION_YES); + } + + RECT rect; + rect.left = headers[NEW_COL].x - scroll_ulc_x; + rect.right = headers[SRC_COL+1].x - scroll_ulc_x; + rect.top = header_height + r * row_height - scroll_ulc_y; + rect.bottom = rect.top + row_height; + InvalidateRect (hwnd, &rect, TRUE); + return FALSE; +} + +static LRESULT CALLBACK +listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_HSCROLL: + return HANDLE_WM_HSCROLL (hwnd, wParam, lParam, list_hscroll); + case WM_VSCROLL: + return HANDLE_WM_VSCROLL (hwnd, wParam, lParam, list_vscroll); + case WM_LBUTTONDOWN: + return HANDLE_WM_LBUTTONDOWN (hwnd, wParam, lParam, list_click); + case WM_PAINT: + paint (hwnd); + return 0; + default: + return DefWindowProc (hwnd, message, wParam, lParam); + } +} + +static void +register_windows (HINSTANCE hinst) +{ + WNDCLASSEX wcex; + static int done = 0; + + if (done) + return; + done = 1; + + memset (&wcex, 0, sizeof (wcex)); + wcex.cbSize = sizeof (WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = listview_proc; + wcex.hInstance = hinst; + wcex.hIcon = LoadIcon (0, IDI_APPLICATION); + wcex.hCursor = LoadCursor (0, IDC_ARROW); + wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); + wcex.lpszClassName = "listview"; + + RegisterClassEx (&wcex); +} + +static void +note_width (HDC dc, char *string, int addend, int column) +{ + if (!string) + return; + SIZE s; + GetTextExtentPoint32 (dc, string, strlen (string), &s); + if (headers[column].width < s.cx + addend) + headers[column].width = s.cx + addend; +} + +static int +best_trust (int p, int trust) +{ + int t; + for (t=trust; t>=0; t--) + if (package[p].info[t].install) + return t; + for (t=trust+1; t<=NTRUST; t++) + if (package[p].info[t].install) + return t; + if (extra[p].installed_file) + return TRUST_KEEP; + return TRUST_NONE; +} + +static void +default_trust (HWND h, int trust) +{ + int i, t, c; + + for (i=0; ileft, r->top, + r->right-r->left+1, r->bottom-r->top+1, + dlg, + NULL, // ??? MAKEINTRESOURCE(IDC_CHOOSE_LIST), + hinstance, + 0); + ShowWindow (lv, SW_SHOW); + + for (i=0; headers[i].text; i++) + headers[i].width = 0; + + HDC dc = GetDC (lv); + sysfont = GetStockObject (DEFAULT_GUI_FONT); + SelectObject (dc, sysfont); + GetTextMetrics (dc, &tm); + header_height = tm.tmHeight + 5 + 3; + + bitmap_dc = CreateCompatibleDC (dc); + + row_height = (tm.tmHeight + tm.tmExternalLeading + ROW_MARGIN); + int irh = tm.tmExternalLeading + tm.tmDescent + 11 + ROW_MARGIN; + if (row_height < irh) + row_height = irh; + + for (i=0; headers[i].text; i++) + note_width (dc, headers[i].text, 0, i); + for (i=0; ileft; + p.y = r->top; + ScreenToClient (parent, &p); + r->left = p.x; + r->top = p.y; + p.x = r->right; + p.y = r->bottom; + ScreenToClient (parent, &p); + r->right = p.x; + r->bottom = p.y; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND frame; + RECT r; + switch (message) + { + case WM_INITDIALOG: + nextbutton = GetDlgItem (h, IDOK); + frame = GetDlgItem (h, IDC_LISTVIEW_POS); + GetParentRect (h, frame, &r); + r.top += 2; + r.bottom -= 2; + create_listview (h, &r); +#if 0 + load_dialog (h); +#endif + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +static char * +base (char *s) +{ + if (!s) + return 0; + char *rv = s; + while (*s) + { + if ((*s == '/' || *s == ':' || *s == '\\') && s[1]) + rv = s+1; + s++; + } + return rv; +} + +static void +scan2 (char *path, unsigned int size) +{ + int i, t; + for (i=0; iname, b->name); +} + +void +do_choose (HINSTANCE h) +{ + int rv, i; + + qsort (package, npackages, sizeof (package[0]), package_sort); + + nextbutton = 0; + bm_spin = LoadImage (h, MAKEINTRESOURCE (IDB_SPIN), IMAGE_BITMAP, 0, 0, 0); + bm_rtarrow = LoadImage (h, MAKEINTRESOURCE (IDB_RTARROW), IMAGE_BITMAP, 0, 0, 0); + + bm_checkyes = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_YES), IMAGE_BITMAP, 0, 0, 0); + bm_checkno = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NO), IMAGE_BITMAP, 0, 0, 0); + bm_checkna = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NA), IMAGE_BITMAP, 0, 0, 0); + + extra = (ExtraPackageInfo *) malloc (npackages * sizeof (ExtraPackageInfo)); + memset (extra, 0, npackages * sizeof (ExtraPackageInfo)); + for (i=0; i + * + */ + +/* See concat.h. Note that we canonicalize the result, this avoids + multiple slashes being interpreted as UNCs. */ + +#include "win32.h" +#include +#include +#include + +char * CDECL +concat (char *s, ...) +{ + int len; + char *rv, *arg; + va_list v; + + if (!s) + return 0; + + len = strlen (s); + + va_start (v, s); + while (1) + { + arg = va_arg (v, char *); + if (arg == 0) + break; + len += strlen (arg); + } + va_end (v); + + rv = (char *) malloc (len+1); + strcpy (rv, s); + va_start (v, s); + while (1) + { + arg = va_arg (v, char *); + if (arg == 0) + break; + strcat (rv, arg); + } + va_end (v); + + /* concat is only used for urls and files, so we can safely + canonicalize the results */ + char *d; + for (s=rv; *s; s++) + if (*s == '\\') + *s = '/'; + for (s=d=rv; *s; s++) + { + *d++ = *s; + /* special case for URLs */ + if (*s == ':' && s[1] == '/' && s[2] == '/' && s > rv+1) + { + *d++ = *++s; + *d++ = *++s; + } + else if (*s == '/') + while (s[1] == '/') + s++; + } + *d = 0; + + return rv; +} + +char * +backslash (char *s) +{ + for (char *t = s; *t; t++) + if (*t == '/') + *t = '\\'; + return s; +} diff --git a/netinstall/concat.h b/netinstall/concat.h new file mode 100644 index 0000000..59ca6a5 --- /dev/null +++ b/netinstall/concat.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Pass a null-terminated list of strings, and it concatenates them + into a single string. Warning - it assumes the result is a file + name or URL, and will canonicalize the result accordingly + (i.e. replace \ with /, collapse multiple /// to a single /, etc.) */ + +char * CDECL concat (char *s, ...); + +/* convert slashes to backslashes */ + +char * backslash (char *s); diff --git a/netinstall/desktop.cc b/netinstall/desktop.cc new file mode 100644 index 0000000..0a7c993 --- /dev/null +++ b/netinstall/desktop.cc @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to manage all the desktop setup, such + as start menu, batch files, desktop icons, and shortcuts. Note + that unlike other do_* functions, this one is called directly from + install.cc */ + + +#include "win32.h" +#include + +#include +#include +#include +#ifndef WIN32_NATIVE +#include +#endif + +#include "resource.h" +#include "ini.h" +#include "msg.h" +#include "state.h" +#include "concat.h" +#include "mkdir.h" +#include "dialog.h" +#include "version.h" +#include "reginfo.h" +#include "regedit.h" +#include "port.h" + +extern "C" { + void make_link_2 (char *exepath, char *args, char *icon, char *lname); +}; + +static OSVERSIONINFO verinfo; + +/* Lines starting with '@' are conditionals - include 'N' for NT, + '5' for Win95, '8' for Win98, '*' for all, like this: + echo foo + @N8 + echo NT or 98 + @* + */ + +#define COMMAND9XARGS "/E:4096 /c" +#define COMMAND9XEXE "\\command.com" + +static char *iconname; +static char *batname; + +static void +make_link (char *linkpath, char *title, char *target) +{ + char argbuf[_MAX_PATH]; + char *fname = concat (linkpath, "/", title, ".lnk", 0); + + if (_access (fname, 0) == 0) + return; /* already exists */ + + msg ("make_link %s, %s, %s\n", fname, title, target); + + mkdir_p (0, fname); + + char *exepath, *args; + + /* If we are running Win9x, build a command line. */ + if (verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + exepath = target; + args = ""; + } + else + { + char windir[MAX_PATH]; + + GetWindowsDirectory (windir, sizeof (windir)); + exepath = concat (windir, COMMAND9XEXE, 0); + sprintf (argbuf, "%s %s", COMMAND9XARGS, target); + args = argbuf; + } + + msg ("make_link_2 (%s, %s, %s, %s)", exepath, args, iconname, fname); + make_link_2 (exepath, args, iconname, fname); +} + +static char* +find_xemacs_exe_path () +{ + if (xemacs_package->type == TY_CYGWIN) + return backslash (concat (root_dir, "/bin/", XEMACS_CYGWIN_ARCH_NAME, 0)); + else + return backslash (concat (root_dir, "\\XEmacs-", + xemacs_package->info[xemacs_package->trust].version, + "\\", XEMACS_NATIVE_ARCH_NAME, 0)); +} + +static char* +find_xemacs_exe_name () +{ + if (xemacs_package->type == TY_CYGWIN) + return backslash (concat ("xemacs-", + xemacs_package->info[xemacs_package->trust].version, + ".exe", 0)); + else + return strdup ("xemacs.exe"); +} + +static void +start_menu (char *title, char *target) +{ + char path[_MAX_PATH]; + LPITEMIDLIST id; + int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0; + SHGetSpecialFolderLocation (NULL, issystem ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, &id); + SHGetPathFromIDList (id, path); +// following lines added because it appears Win95 does not use common programs +// unless it comes into play when multiple users for Win95 is enabled + msg("Program directory for program link: %s",path); + if ( strlen(path) == 0) { + SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id); + SHGetPathFromIDList (id, path); + msg("Program directory for program link changed to: %s",path); + } +// end of Win95 addition + strcat (path, "/"); + strcat (path, XEMACS_INFO_XEMACS_ORG_REGISTRY_NAME); + make_link (path, title, target); +} + +static void +desktop_icon (char *title, char *target) +{ + char path[_MAX_PATH]; + LPITEMIDLIST id; + int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0; + //SHGetSpecialFolderLocation (NULL, issystem ? CSIDL_DESKTOP : CSIDL_COMMON_DESKTOPDIRECTORY, &id); + SHGetSpecialFolderLocation (NULL, issystem ? CSIDL_COMMON_DESKTOPDIRECTORY : CSIDL_DESKTOPDIRECTORY, &id); + SHGetPathFromIDList (id, path); +// following lines added because it appears Win95 does not use common programs +// unless it comes into play when multiple users for Win95 is enabled + msg("Desktop directory for desktop link: %s",path); + if ( strlen(path) == 0) { + SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id); + SHGetPathFromIDList (id, path); + msg("Desktop directory for deskop link changed to: %s",path); + } +// end of Win95 addition + make_link (path, title, target); +} + +static int +uexists (char *path) +{ + char *f = concat (root_dir, path, 0); + int a = _access (f, 0); + free (f); + if (a == 0) + return 1; + return 0; +} + +static void +make_passwd_group () +{ + if (verinfo.dwPlatformId != VER_PLATFORM_WIN32_NT) + { + int i; + + LOOP_PACKAGES + { + if (!strcmp (package[i].name, "cygwin")) + { + /* mkpasswd and mkgroup are not working on 9x/ME up to 1.1.5-4 */ + char *border_version = canonicalize_version ("1.1.5-4"); + char *inst_version = canonicalize_version (pi.version); + + if (strcmp (inst_version, border_version) <= 0) + return; + + break; + } + } + } + + if (uexists ("/etc/passwd") && uexists ("/etc/group")) + return; + + char *fname = concat (root_dir, "/etc/postinstall/passwd-grp.bat", 0); + mkdir_p (0, fname); + + FILE *p = fopen (fname, "wb"); + if (!p) + return; + + if (!uexists ("/etc/passwd")) + fprintf (p, "bin\\mkpasswd -l > etc\\passwd\n"); + if (!uexists ("/etc/group")) + fprintf (p, "bin\\mkgroup -l > etc\\group\n"); + + fclose (p); +} + +static void +save_icon () +{ + iconname = backslash (concat (root_dir, XEMACS_RESOURCE_DIR, + "xemacs.ico", 0)); + + HRSRC rsrc = FindResource (NULL, "XEMACS.ICON", "FILE"); + if (rsrc == NULL) + { + fatal ("FindResource failed"); + } + HGLOBAL res = LoadResource (NULL, rsrc); + char *data = (char *) LockResource (res); + int len = SizeofResource (NULL, rsrc); + + FILE *f = fopen (iconname, "wb"); + if (f) + { + fwrite (data, 1, len, f); + fclose (f); + } +} + +static void +do_desktop_setup() +{ + save_icon (); + + if (root_menu && batname) { + start_menu ("XEmacs", batname); + } + + if (root_desktop && batname) { + desktop_icon ("XEmacs", batname); + } + + // set regkeys for the application + if (xemacs_package != 0) + { + int issystem = (root_scope == IDC_ROOT_SYSTEM ? 1 : 0); + if (xemacs_package->type == TY_NATIVE) + { +#define FROB(exe) set_app_path ((exe), \ + find_xemacs_exe_path (), \ + issystem) + FROB (find_xemacs_exe_name ()); + FROB ("runemacs.exe"); + FROB ("xemacs.exe"); +#undef FROB + } + else if (xemacs_package->type == TY_CYGWIN) + { + int junk; + char* root = find_cygwin_root (&junk); +#define FROB(exe) set_app_path ((exe), \ + concat (find_xemacs_exe_path (), ";", \ + root, "\\bin;", \ + root, "\\usr\\bin", 0), \ + issystem) + FROB (find_xemacs_exe_name ()); + FROB ("runemacs.exe"); + FROB ("xemacs.exe"); +#undef FROB + } + } +} + +static int da[] = { IDC_ROOT_DESKTOP, 0 }; +static int ma[] = { IDC_ROOT_MENU, 0 }; + +static void +check_if_enable_next (HWND h) +{ + EnableWindow (GetDlgItem (h, IDOK), 1); +} + +static void +load_dialog (HWND h) +{ + rbset (h, da, root_desktop); + rbset (h, ma, root_menu); + check_if_enable_next (h); +} + +static int check_desktop (char *title, char *target) +{ + char path[_MAX_PATH]; + LPITEMIDLIST id; + int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0; + SHGetSpecialFolderLocation (NULL, issystem ? CSIDL_COMMON_DESKTOPDIRECTORY : CSIDL_DESKTOPDIRECTORY, &id); + SHGetPathFromIDList (id, path); + // following lines added because it appears Win95 does not use common programs + // unless it comes into play when multiple users for Win95 is enabled + msg ("Desktop directory for desktop link: %s",path); + if (strlen (path) == 0) { + SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id); + SHGetPathFromIDList (id, path); + msg ("Desktop directory for deskop link changed to: %s",path); + } + // end of Win95 addition + char *fname = concat (path, "/", title, ".lnk", 0); + + if (_access (fname, 0) == 0) + return 0; /* already exists */ + + fname = concat (path, "/", title, ".pif", 0); /* check for a pif as well */ + + if (_access (fname, 0) == 0) + return 0; /* already exists */ + + return IDC_ROOT_DESKTOP; +} + +static int check_startmenu (char *title, char *target) +{ + char path[_MAX_PATH]; + LPITEMIDLIST id; + int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0; + SHGetSpecialFolderLocation (NULL, issystem ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, &id); + SHGetPathFromIDList (id, path); + // following lines added because it appears Win95 does not use common programs + // unless it comes into play when multiple users for Win95 is enabled + msg ("Program directory for program link: %s",path); + if (strlen (path) == 0) { + SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id); + SHGetPathFromIDList (id, path); + msg ("Program directory for program link changed to: %s",path); + } + // end of Win95 addition + strcat (path, "/"); + strcat (path, XEMACS_INFO_XEMACS_ORG_REGISTRY_NAME); + char *fname = concat (path, "/", title, ".lnk", 0); + + if (_access (fname, 0) == 0) + return 0; /* already exists */ + + fname = concat (path, "/", title, ".pif", 0); /* check for a pif as well */ + + if (_access (fname, 0) == 0) + return 0; /* already exists */ + + return IDC_ROOT_MENU; +} + +static void +save_dialog (HWND h) +{ + root_desktop= rbget (h, da); + root_menu = rbget (h, ma); +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_ROOT_DESKTOP: + case IDC_ROOT_MENU: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDOK: + save_dialog (h); + do_desktop_setup(); + NEXT (IDD_S_POSTINSTALL); + break; + + case IDC_BACK: + save_dialog (h); + NEXT (IDD_CHOOSE); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +void +do_desktop (HINSTANCE h) +{ + CoInitialize (NULL); + + verinfo.dwOSVersionInfoSize = sizeof (verinfo); + GetVersionEx (&verinfo); + batname = 0; + + if (xemacs_package != 0 && xemacs_package->type != TY_GENERIC) + { + batname = concat (find_xemacs_exe_path (), "\\", + find_xemacs_exe_name (), 0); + root_desktop = check_desktop ("XEmacs", batname); + root_menu = check_startmenu ("XEmacs", batname); + } + else + { + root_desktop = 0; + root_menu = 0; + } + + int rv = 0; + + rv = DialogBox (h, MAKEINTRESOURCE (IDD_DESKTOP), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); +} diff --git a/netinstall/dialog.cc b/netinstall/dialog.cc new file mode 100644 index 0000000..43bedd5 --- /dev/null +++ b/netinstall/dialog.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to provide common functionality for + all the dialogs in the program. */ + +#include "win32.h" +#include +#include +#include "dialog.h" +#include "msg.h" +#include "log.h" + +char * +eget (HWND h, int id, char *var) +{ + char tmp[4000]; + if (var) + { + free (var); + var = 0; + } + if (GetDlgItemText (h, id, tmp, sizeof (tmp)) > 0) + { + var = (char *) malloc (strlen (tmp)+1); + strcpy (var, tmp); + } + return var; +} + +int +eget (HWND h, int id) +{ + BOOL s; + int r = GetDlgItemInt (h, id, &s, TRUE); + return r; +} + +void +eset (HWND h, int id, char *val) +{ + SetDlgItemText (h, id, val); +} + +void +eset (HWND h, int id, int val) +{ + SetDlgItemInt (h, id, (UINT)val, TRUE); +} + +int +rbget (HWND h, int *ids) +{ + int i; + for (i=0; ids[i]; i++) + if (IsDlgButtonChecked (h, ids[i]) == BST_CHECKED) + return ids[i]; + return 0; +} + +void +rbset (HWND h, int *ids, int id) +{ + int i; + for (i=0; ids[i]; i++) + CheckDlgButton (h, ids[i], id==ids[i] ? BST_CHECKED : BST_UNCHECKED); +} + +void +fatal (char *m) +{ + DWORD e = GetLastError (); + char *buf; + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + 0, + e, + 0, + (CHAR *)&buf, + 0, + 0); + MessageBox (0, buf, m, 0); + exit_setup (1); +} diff --git a/netinstall/dialog.h b/netinstall/dialog.h new file mode 100644 index 0000000..44c6f9c --- /dev/null +++ b/netinstall/dialog.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* global instance for the application; set in main.cc */ +extern HINSTANCE hinstance; + +/* used by main.cc to select the next do_* function */ +extern int next_dialog; + +/* either "nothing to do" or "setup complete" or something like that */ +extern int exit_msg; + +#define D(x) void x(HINSTANCE _h) + +/* prototypes for all the do_* functions (most called by main.cc) */ + +D(do_choose); +D(do_desktop); +D(do_download); +D(do_fromcwd); +D(do_ini); +D(do_install); +D(do_local_dir); +D(do_net); +D(do_other); +D(do_postinstall); +D(do_root); +D(do_site); +D(do_source); +D(do_splash); + +#undef D + +/* end this dialog and select the next. Pass 0 to exit the program */ +#define NEXT(id) EndDialog((HWND)h, 0), next_dialog = id + +/* Get the value of an EditText control. Pass the previously stored + value and it will free the memory if needed. */ + +char *eget (HWND h, int id, char *var); + +/* Same, but convert the value to an integer */ + +int eget (HWND h, int id); + +/* Set the EditText control to the given string or integer */ + +void eset (HWND h, int id, char *var); +void eset (HWND h, int id, int var); + +/* RadioButtons. ids is a null-terminated list of IDs. Get + returns the selected ID (or zero), pass an ID to set */ + +int rbget (HWND h, int *ids); +void rbset (HWND h, int *ids, int id); + +/* *This* version of fatal (compare with msg.h) uses GetLastError() to + format a suitable error message. Similar to perror() */ + +void fatal (char *msg); diff --git a/netinstall/diskfull.cc b/netinstall/diskfull.cc new file mode 100644 index 0000000..3b8961d --- /dev/null +++ b/netinstall/diskfull.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to hide the mess needed just to figure + out how full a given disk is. There is an old API that can't + handle disks bigger than 2G, and a new API that isn't always + available. */ + +#include "win32.h" +#include "diskfull.h" + +typedef BOOL (WINAPI * GDFS)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, + PULARGE_INTEGER); + +int +diskfull (char *path) +{ + GDFS gdfs = 0; + + HINSTANCE k = LoadLibrary ("KERNEL32.DLL"); + if (k) + { + gdfs = (GDFS) GetProcAddress (k, "GetDiskFreeSpaceExA"); + + if (gdfs) + { + ULARGE_INTEGER avail, total, free; + if (gdfs (path, &avail, &total, &free)) + { + int perc = avail.QuadPart * 100 / total.QuadPart; + return 100-perc; + } + } + } + + char root[4]; + if (path[1] != ':') + return 0; + + root[0] = path[0]; + root[1] = ':'; + root[2] = '\\'; + root[3] = 0; + + DWORD junk, free_clusters, total_clusters; + + if (GetDiskFreeSpace (root, &junk, &junk, &free_clusters, &total_clusters)) + { + int perc = free_clusters * 100 / total_clusters; + return 100-perc; + } + + return 0; +} diff --git a/netinstall/diskfull.h b/netinstall/diskfull.h new file mode 100644 index 0000000..e198a74 --- /dev/null +++ b/netinstall/diskfull.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* returns 0..100 (percent) */ +int diskfull (char *path); diff --git a/netinstall/download.cc b/netinstall/download.cc new file mode 100644 index 0000000..3b6ad95 --- /dev/null +++ b/netinstall/download.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to download all the files we need to + do the installation. */ + +#include +#include +#include + +#include "win32.h" + +#include "resource.h" +#include "msg.h" +#include "ini.h" +#include "dialog.h" +#include "concat.h" +#include "geturl.h" +#include "state.h" +#include "mkdir.h" +#include "log.h" + +#define pi (package[i].info[package[i].trust]) + +static int +download_one (char *name, int expected_size) +{ + char *local = name; + + struct stat s; + if (stat (local, &s) >= 0) + if (s.st_size == expected_size) + return 0; + + mkdir_p (0, local); + + if (get_url_to_file (concat (MIRROR_SITE, "/", name, 0), + concat (local, ".tmp", 0), + expected_size)) + { + note (IDS_DOWNLOAD_FAILED, name); + return 1; + } + else + { + stat (concat (local, ".tmp", 0), &s); + if (s.st_size == expected_size) + { + log (0, "Downloaded %s", local); + rename (concat (local, ".tmp", 0), local); + } + else + { + log (0, "Download %s wrong size (%d actual vs %d expected)", + local, s.st_size, expected_size); + note (IDS_DOWNLOAD_SHORT, local, s.st_size, expected_size); + return 1; + } + } + + return 0; +} + +void +do_download (HINSTANCE h) +{ + int i; + int errors = 0; + + for (i=0; i + * + */ + +/* The purpose of this file is to doa recursive find on a given + directory, calling a given function for each file found. */ + +#include "win32.h" +#include +#include + +#include "port.h" + +static void (*for_each)(char *, unsigned int); +static char dir[_MAX_PATH], *found_part; + +static int +find_sub () +{ + WIN32_FIND_DATA wfd; + HANDLE h; + char *end = dir + strlen (dir); + int rv = 0; + + *end++ = '/'; + strcpy (end, "*"); + + h = FindFirstFile (dir, &wfd); + + if (h == INVALID_HANDLE_VALUE) + return 0; + + do { + if (strcmp (wfd.cFileName, ".") == 0 + || strcmp (wfd.cFileName, "..") == 0) + continue; + + strcpy (end, wfd.cFileName); + + if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + find_sub (); + else + { + for_each (found_part, wfd.nFileSizeLow); + rv ++; + } + + } while (FindNextFile (h, &wfd)); + + FindClose (h); + return rv; +} + +int +find (char *starting_dir, void (*_for_each)(char *, unsigned int)) +{ + strcpy (dir, starting_dir); + for_each = _for_each; + found_part = dir + strlen (dir) + 1; + + return find_sub (); +} diff --git a/netinstall/find.h b/netinstall/find.h new file mode 100644 index 0000000..4c38913 --- /dev/null +++ b/netinstall/find.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The for_each function is called once for each file found in the + starting_dir or any subdir (recursively), passing the relative path + (i.e. it doesn't include "starting_dir") and the size of the file + (bytes). find() returns the number of files found. Directories + are scanned but not included in the "found" files. */ + +extern int find (char *starting_dir, void (*for_each)(char *, unsigned int)); diff --git a/netinstall/fromcwd.cc b/netinstall/fromcwd.cc new file mode 100644 index 0000000..0fadb7b --- /dev/null +++ b/netinstall/fromcwd.cc @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to handle the case where we're + installing from files that already exist in the current directory. + If a setup.ini file is present, we set the mirror site to "." and + pretend we're installing from the `internet' ;-) else we have to + find all the .tar.gz files, deduce their versions, and try to + compare versions in the case where the current directory contains + multiple versions of any given package. We do *not* try to compare + versions with already installed packages; we always choose a + package in the current directory over one that's already installed + (otherwise, why would you have asked to install it?). Note + that we search recursively. */ + +#include "win32.h" + +#include +#include +#include +#include +#ifndef WIN32_NATIVE +#include +#endif + +#include "ini.h" +#include "resource.h" +#include "concat.h" +#include "state.h" +#include "dialog.h" +#include "msg.h" +#include "find.h" +#include "version.h" + +#include "port.h" + +static int +is_test_version (char *v) +{ + int i; + for (i=0; v[i] && isdigit (v[i]); i++) ; + return (i >= 6) ? 1 : 0; +} + +char * +canonicalize_version (char *v) +{ + static char nv[3][100]; + static int idx = 0; + char *np, *dp; + int i; + + idx = (idx+1) % 3; + np = nv[idx]; + + while (*v) + { + if (isdigit (*v)) + { + for (dp=v; *dp && isdigit (*dp); dp++) ; + for (i=dp-v; i<12; i++) + *np++ = '0'; + while (v < dp) + *np++ = *v++; + } + else + *np++ = *v++; + } + *np++ = 0; + return nv[idx]; +} + +static void +found_file (char *path, unsigned int fsize) +{ + char base[_MAX_PATH], *ver; + + int l = strlen (path); + + if (strcmp (path + l - 7, ".tar.gz") != 0) + return; + if (strstr (path, "-src.")) + return; + if (strstr (path, "-patch.")) + return; + + char *sl = strrchr (path, '/'); + if (sl) + sl ++; + else + sl = path; + strcpy (base, sl); + base[strlen (base) - 7] = 0; /* remove .tar.gz */ + for (ver=base; *ver; ver++) + if ((*ver == '-' || *ver == '_') && isdigit (ver[1])) + { + *ver++ = 0; + break; + } + + Package *p = 0; + int i; + + for (i=0; iinfo[trust].version) + { + char *ov = canonicalize_version (p->info[trust].version); + char *nv = canonicalize_version (ver); + if (strcmp (ov, nv) > 0) + return; + } + + l = strlen (base); + if (l >= 5 && strcmp (base + l - 5, "win32") == 0) + p->type = TY_NATIVE; + if (l >= 8 && strcmp (base + l - 8, "cygwin32") == 0) + p->type = TY_CYGWIN; + + p->info[trust].version = strdup (ver); + p->info[trust].install = strdup (path); + p->info[trust].install_size = fsize; +} + +void +do_fromcwd (HINSTANCE h) +{ + if (_access ("./setup.ini", 0) == 0) + { + mirror_site = "."; + next_dialog = IDD_S_LOAD_INI; + return; + } + + next_dialog = IDD_CHOOSE; + + find (".", found_file); + + // Now see about source tarballs + int i, t; + Package *p; + char srcpath[_MAX_PATH]; + for (i=0; iinfo[t].install) + { + strcpy (srcpath, p->info[t].install); + strcpy (srcpath + strlen (srcpath) - 7, "-src.tar.gz"); + msg ("looking for %s", srcpath); + + WIN32_FIND_DATA wfd; + HANDLE h = FindFirstFile (srcpath, &wfd); + if (h != INVALID_HANDLE_VALUE) + { + msg("-- got it"); + FindClose (h); + p->info[t].source = strdup (srcpath); + p->info[t].source_size = wfd.nFileSizeLow; + } + } + } + + return; +} diff --git a/netinstall/geturl.cc b/netinstall/geturl.cc new file mode 100644 index 0000000..864319f --- /dev/null +++ b/netinstall/geturl.cc @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to act as a pretty interface to + netio.cc. We add a progress dialog and some convenience functions + (like collect to string or file */ + +#include "win32.h" +#include "commctrl.h" + +#include +#include +#include + +#include "dialog.h" +#include "geturl.h" +#include "resource.h" +#include "netio.h" +#include "msg.h" +#include "log.h" + +static int is_showing = 0; +static HWND gw_dialog = 0; +static HWND gw_url = 0; +static HWND gw_rate = 0; +static HWND gw_progress = 0; +static HANDLE init_event; +static int max_bytes = 0; + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + case IDCANCEL: + exit_setup (0); + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + gw_dialog = h; + gw_url = GetDlgItem (h, IDC_DLS_URL); + gw_rate = GetDlgItem (h, IDC_DLS_RATE); + gw_progress = GetDlgItem (h, IDC_DLS_PROGRESS); + SetEvent (init_event); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +static DWORD WINAPI +dialog (void *) +{ + MSG m; + HWND gw_dialog = CreateDialog (hinstance, MAKEINTRESOURCE (IDD_DLSTATUS), + 0, dialog_proc); + ShowWindow (gw_dialog, SW_SHOWNORMAL); + UpdateWindow (gw_dialog); + while (GetMessage (&m, 0, 0, 0) > 0) { + TranslateMessage (&m); + DispatchMessage (&m); + } + return FALSE; +} + +static DWORD start_tics; + +static void +init_dialog (char *url, int length) +{ + if (gw_dialog == 0) + { + DWORD tid; + HANDLE thread; + init_event = CreateEvent (0, 0, 0, 0); + thread = CreateThread (0, 0, dialog, 0, 0, &tid); + WaitForSingleObject (init_event, 1000); + CloseHandle (init_event); + SendMessage (gw_progress, PBM_SETRANGE, 0, MAKELPARAM (0, 100)); + is_showing = 0; + } + char *sl=url, *cp; + for (cp=url; *cp; cp++) + if (*cp == '/' || *cp == '\\' || *cp == ':') + sl = cp+1; + max_bytes = length; + SetWindowText (gw_url, sl); + SetWindowText (gw_rate, "Connecting..."); + SendMessage (gw_progress, PBM_SETPOS, (WPARAM) 0, 0); + ShowWindow (gw_progress, (length > 0) ? SW_SHOW : SW_HIDE); + ShowWindow (gw_dialog, SW_SHOWNORMAL); + if (!is_showing) + { + SetForegroundWindow (gw_dialog); + is_showing = 1; + } + start_tics = GetTickCount (); +} + + +static void +progress (int bytes) +{ + static char buf[100]; + int kbps; + static DWORD last_tics = 0; + DWORD tics = GetTickCount (); + if (tics == start_tics) // to prevent division by zero + return; + if (tics < last_tics + 200) // to prevent flickering updates + return; + last_tics = tics; + + kbps = bytes / (tics - start_tics); + ShowWindow (gw_progress, (max_bytes > 0) ? SW_SHOW : SW_HIDE); + if (max_bytes > 100) + { + int perc = bytes / (max_bytes / 100); + SendMessage (gw_progress, PBM_SETPOS, (WPARAM) perc, 0); + sprintf (buf, "%3d %% (%dk/%dk) %d kb/s\n", + perc, bytes/1000, max_bytes/1000, kbps); + } + else + sprintf (buf, "%d %d kb/s\n", bytes, kbps); + + SetWindowText (gw_rate, buf); +} + +struct GUBuf { + GUBuf *next; + int count; + char buf[2000]; +}; + +char * +get_url_to_string (char *_url) +{ + log (LOG_BABBLE, "get_url_to_string %s", _url); + init_dialog (_url, 0); + NetIO *n = NetIO::open (_url); + if (!n || !n->ok ()) + { + delete n; + log (LOG_BABBLE, "get_url_to_string failed!"); + return 0; + } + + if (n->file_size) + max_bytes = n->file_size; + + GUBuf *bufs = 0; + GUBuf **nextp = &bufs; + int total_bytes = 1; /* for the NUL */ + progress (0); + while (1) + { + GUBuf *b = new GUBuf; + *nextp = b; + b->next = 0; + nextp = &(b->next); + + b->count = n->read (b->buf, sizeof (b->buf)); + if (b->count <= 0) + break; + total_bytes += b->count; + progress (total_bytes); + } + + char *rv = (char *) malloc (total_bytes); + char *rvp = rv; + while (bufs && bufs->count > 0) + { + GUBuf *tmp = bufs->next; + memcpy (rvp, bufs->buf, bufs->count); + rvp += bufs->count; + delete bufs; + bufs = tmp; + } + *rvp = 0; + return rv; +} + +int +get_url_to_file (char *_url, char *_filename, int expected_length) +{ + log (LOG_BABBLE, "get_url_to_file %s %s", _url, _filename); + init_dialog (_url, expected_length); + + remove (_filename); /* but ignore errors */ + + NetIO *n = NetIO::open (_url); + if (!n || !n->ok ()) + { + delete n; + log (LOG_BABBLE, "get_url_to_file failed!"); + return 1; + } + + FILE *f = fopen (_filename, "wb"); + if (!f) + { + char *err = strerror (errno); + if (!err) + err = "(unknown error)"; + fatal (IDS_ERR_OPEN_WRITE, _filename, err); + } + + if (n->file_size) + max_bytes = n->file_size; + + int total_bytes = 0; + progress (0); + while (1) + { + char buf[8192]; + int count; + count = n->read (buf, sizeof (buf)); + if (count <= 0) + break; + fwrite (buf, 1, count, f); + total_bytes += count; + progress (total_bytes); + } + + fclose (f); + + return 0; +} + +void +dismiss_url_status_dialog () +{ + ShowWindow (gw_dialog, SW_HIDE); + is_showing = 0; +} diff --git a/netinstall/geturl.h b/netinstall/geturl.h new file mode 100644 index 0000000..32a7b3d --- /dev/null +++ b/netinstall/geturl.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Download files from the Internet. These pop up a progress dialog; + don't forget to dismiss it when you're done downloading for a while */ + +char *get_url_to_string (char *_url); +int get_url_to_file (char *_url, char *_filename, int expected_size); +void dismiss_url_status_dialog (); diff --git a/netinstall/gnu.bmp b/netinstall/gnu.bmp new file mode 100644 index 0000000..f6d56f9 Binary files /dev/null and b/netinstall/gnu.bmp differ diff --git a/netinstall/hash.cc b/netinstall/hash.cc new file mode 100644 index 0000000..01a110e --- /dev/null +++ b/netinstall/hash.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Simple hash class for install.cc */ + +#include "win32.h" +#include +#include + +#include "hash.h" + +class hash_internals { +public: + char **keys; + int numkeys; + int maxkeys; + int prev_index; +}; + +hash::hash () +{ + h = new hash_internals; + h->numkeys = 0; + h->maxkeys = 10; + h->keys = (char **) malloc (h->maxkeys * sizeof (char *)); + h->prev_index = 0; +} + +hash::~hash () +{ + free (h->keys); + free (h); +} + + +void +hash::add (char *string) +{ + int i; + for (i=0; inumkeys; i++) + if (strcmp (h->keys[i], string) == 0) + return; + if (h->numkeys >= h->maxkeys) + { + h->maxkeys += 10; + h->keys = (char **) realloc (h->keys, h->maxkeys * sizeof (char *)); + } + + h->keys[h->numkeys] = _strdup (string); + h->numkeys ++; +} + + +int +hash::has (char *string) +{ + int i; + for (i=0; inumkeys; i++) + if (strcmp (h->keys[i], string) == 0) + return 1; + return 0; +} + +char * +hash::enumerate (char *prev) +{ + if (prev == 0) + h->prev_index = -1; + h->prev_index ++; + if (h->prev_index >= h->numkeys) + return 0; + return h->keys[h->prev_index]; +} + +static int CDECL +rev_len (const void *va, const void *vb) +{ + char *a = *(char **)va; + char *b = *(char **)vb; + return strcmp (b, a); +} + +void +hash::reverse_sort () +{ + qsort (h->keys, h->numkeys, sizeof (h->keys[0]), rev_len); +} diff --git a/netinstall/hash.h b/netinstall/hash.h new file mode 100644 index 0000000..2f5407a --- /dev/null +++ b/netinstall/hash.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Simple hash class for install.cc */ + +class hash_internals; + +class hash { + hash_internals *h; + public: + hash (); + ~hash (); + + void add (char *string); + int has (char *string); + + /* specialty for install.cc */ + void add_subdirs (char *path); + void reverse_sort (); + + char *enumerate (char *prev=0); +}; diff --git a/netinstall/ini.cc b/netinstall/ini.cc new file mode 100644 index 0000000..cd2a847 --- /dev/null +++ b/netinstall/ini.cc @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to get and parse the setup.ini file + from the mirror site. A few support routines for the bison and + flex parsers are provided also. We check to see if this setup.ini + is older than the one we used last time, and if so, warn the user. */ + +#include "win32.h" + +#include +#include +#include + +#include "ini.h" +#include "resource.h" +#include "concat.h" +#include "state.h" +#include "geturl.h" +#include "dialog.h" +#include "msg.h" +#include "mkdir.h" +#include "log.h" +#include "reginfo.h" +#include "version.h" + +unsigned int setup_timestamp = 0; +char *setup_version = 0; + +extern "C" int yyparse (); +/*extern int yydebug;*/ + +static char *error_buf = 0; +static int error_count = 0; + +void +do_ini (HINSTANCE h) +{ + char *ini_file = get_url_to_string (concat (MIRROR_SITE, "/setup.ini", 0)); + dismiss_url_status_dialog (); + + if (!ini_file) + { + note (IDS_SETUPINI_MISSING, MIRROR_SITE); + next_dialog = IDD_SITE; + return; + } + + package = 0; + npackages = 0; + setup_timestamp = 0; + setup_version = 0; + + ini_init (ini_file); + + setup_timestamp = 0; + /*yydebug = 1;*/ + + if (yyparse () || error_count > 0) + { + if (error_count == 1) + MessageBox (0, error_buf, "Parse Error", 0); + else + MessageBox (0, error_buf, "Parse Errors", 0); + } + else + { + /* save known-good setup.ini locally */ + FILE *inif = fopen ("setup.ini", "wb"); + if (inif) + { + fwrite (ini_file, 1, strlen (ini_file), inif); + fclose (inif); + } + } + + if (root_dir) + { + mkdir_p (1, concat (root_dir, XEMACS_SETUP_DIR, 0)); + + unsigned int old_timestamp = 0; + FILE *ots = fopen (concat (root_dir, XEMACS_SETUP_DIR, "timestamp", 0), "rt"); + if (ots) + { + fscanf (ots, "%u", &old_timestamp); + fclose (ots); + if (old_timestamp && setup_timestamp + && (old_timestamp > setup_timestamp)) + { + int yn = yesno (IDS_OLD_SETUPINI); + if (yn == IDNO) + exit_setup (1); + } + } + if (setup_timestamp) + { + FILE *nts = fopen (concat (root_dir, XEMACS_SETUP_DIR, "timestamp", 0), "wt"); + if (nts) + { + fprintf (nts, "%u", setup_timestamp); + fclose (nts); + } + } + } + + msg ("setup_version is %s, our_version is %s", setup_version? setup_version : "(null)", version); + if (setup_version) + { + char *ini_version = canonicalize_version (setup_version); + char *our_version = canonicalize_version (version); + if (strcmp (our_version, ini_version) < 0) + note (IDS_OLD_SETUP_VERSION, version, setup_version); + } + + next_dialog = IDD_CHOOSE; +} + +extern "C" int yylineno; + +extern "C" int CDECL yyerror (char *s, ...) +{ + char buf[1000]; + int len; + sprintf (buf, "setup.ini line %d: ", yylineno); + va_list args; + va_start (args, s); + vsprintf (buf + strlen (buf), s, args); + OutputDebugString (buf); + if (error_buf) + { + strcat (error_buf, "\n"); + len = strlen (error_buf) + strlen (buf) + 5; + error_buf = (char *) realloc (error_buf, len); + strcat (error_buf, buf); + } + else + { + len = strlen (buf) + 5; + error_buf = (char *) malloc (len); + strcpy (error_buf, buf); + } + error_count++; + return 0; +} + +extern "C" int CDECL fprintf (FILE *f, const char *s, ...); + +static char stderrbuf[1000]; + +int CDECL +fprintf (FILE *f, const char *fmt, ...) +{ + char buf[1000]; + int rv; + va_list args; + va_start (args, fmt); + if (f == stderr) + { + rv = vsprintf (buf, fmt, args); + strcat (stderrbuf, buf); + if (char *nl = strchr (stderrbuf, '\n')) + { + *nl = 0; + /*OutputDebugString (stderrbuf);*/ + MessageBox (0, buf, "XEmacs Setup", 0); + stderrbuf[0] = 0; + } + + } + else + { + rv = vfprintf (f, fmt, args); + } + return rv; +} diff --git a/netinstall/ini.h b/netinstall/ini.h new file mode 100644 index 0000000..6e5eab2 --- /dev/null +++ b/netinstall/ini.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* When setup.ini is parsed, the information is stored according to + the declarations here. ini.cc (via inilex and iniparse) + initializes these structures. choose.cc sets the action and trust + fields. download.cc downloads any needed files for selected + packages (the chosen "install" field). install.cc installs + selected packages. */ + +#define YYSTYPE char * + +/* lowest number must be most trusted, highest least trusted */ +#define TRUST_PREV 0 +#define TRUST_CURR 1 +#define TRUST_TEST 2 +#define NTRUST 3 +#define TRUST_UNKNOWN 3 /* intentionally not in NTRUST */ + +#define TY_GENERIC 0 +#define TY_CYGWIN 1 +#define TY_NATIVE 2 + +#define ACTION_UNKNOWN 0 +#define ACTION_SAME 1 +#define ACTION_NEW 2 +#define ACTION_UPGRADE 3 +#define ACTION_UNINSTALL 4 +#define ACTION_ERROR 5 + +#define SRCACTION_NO 0 +#define SRCACTION_YES 1 + +typedef struct { + char *name; /* package name, like "cygwin" */ + char *sdesc; /* short description (replaces "name" if provided) */ + char *ldesc; /* long description (multi-line) */ + int action; /* ACTION_* - only NEW and UPGRADE get installed */ + int srcaction;/* SRCACTION_ */ + int trust; /* TRUST_* (selects among info[] below) */ + int type; /* TY_GENERIC, TY_CYGWIN or TY_NATIVE. */ + + struct { + char *version; /* version part of filename */ + char *install; /* file name to install */ + int install_size; /* in bytes */ + char *source; /* sources for installed binaries */ + int source_size; /* in bytes */ + } info[NTRUST+1]; /* +1 for TRUST_UNKNOWN */ +} Package; + +extern Package *package; +extern Package *xemacs_package; + +extern int npackages; + +#ifdef __cplusplus +extern "C" { +#endif + +Package *new_package (char *name); +void ini_init (char *string); + +#define pi (package[i].info[package[i].trust]) + +#define LOOP_PACKAGES \ + for (i=0; i + * + */ + +/* tokenize the setup.ini files. We parse a string which we've + previously downloaded. The program must call ini_init() to specify + that string. */ + +#include "win32.h" +#include +#include + +#include "ini.h" +#include "iniparse.h" + +#define YY_INPUT(buf,result,max_size) { result = ini_getchar(buf, max_size); } + +static int ini_getchar(char *buf, int max_size); +static void ignore_line (); + +%} + +/*%option debug */ +%option noyywrap +%option yylineno +%option never-interactive + +STR [a-zA-Z0-9_./-]+ + +%% + +\"[^"]*\" { yylval = strdup (yytext+1); + yylval[strlen (yylval)-1] = 0; + return STRING; } + +"setup-timestamp:" return SETUP_TIMESTAMP; +"setup-version:" return SETUP_VERSION; +"version:" return VERSION; +"install:" return INSTALL; +"type:" return TYPE; +"source:" return SOURCE; +"sdesc:" return SDESC; +"ldesc:" return LDESC; + +^{STR}":" ignore_line (); + +"[curr]" return T_CURR; +"[test]" return T_TEST; +"[exp]" return T_TEST; +"[prev]" return T_PREV; +"["{STR}"]" return T_UNKNOWN; + +{STR} { yylval = strdup (yytext); + return STRING; } + +[ \t\r]+ /* do nothing */ + +"#".*\n /* ignore comments */ + +\n { return yytext[0]; } +. { return yytext[0]; } + +%% + +static char *input_string = 0; +static char *end_input_string; + +void +ini_init(char *string) +{ + input_string = string; + end_input_string = input_string + strlen(input_string); +} + +static int +ini_getchar(char *buf, int max_size) +{ + if (input_string) + { + int avail = end_input_string - input_string; + if (avail == 0) + { + input_string = end_input_string = 0; + return 0; + } + if (avail > max_size) + avail = max_size; + memcpy(buf, input_string, avail); + input_string += avail; + return avail; + } + else + return 0; +} + +static void +ignore_line () +{ + char c; + while (c = input ()) + { + if (c == EOF) + return; + if (c == '\n') + return; + } +} diff --git a/netinstall/iniparse.h b/netinstall/iniparse.h new file mode 100644 index 0000000..d8b2c85 --- /dev/null +++ b/netinstall/iniparse.h @@ -0,0 +1,19 @@ +#ifndef YYSTYPE +#define YYSTYPE int +#endif +#define STRING 257 +#define SETUP_TIMESTAMP 258 +#define SETUP_VERSION 259 +#define VERSION 260 +#define INSTALL 261 +#define SOURCE 262 +#define SDESC 263 +#define LDESC 264 +#define TYPE 265 +#define T_PREV 266 +#define T_CURR 267 +#define T_TEST 268 +#define T_UNKNOWN 269 + + +extern YYSTYPE yylval; diff --git a/netinstall/iniparse.y b/netinstall/iniparse.y new file mode 100644 index 0000000..1e78486 --- /dev/null +++ b/netinstall/iniparse.y @@ -0,0 +1,134 @@ +%{ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Parse the setup.ini files. inilex.l provides the tokens for this. */ + +#include +#include +#include +#include "win32.h" + +#include "ini.h" +#include "iniparse.h" + +#include "port.h" + +#define YYERROR_VERBOSE 1 +/*#define YYDEBUG 1*/ + +static Package *cp; +static int trust; +extern unsigned int setup_timestamp; +extern char *setup_version; +extern int yylineno; +extern int CDECL yyerror (char *s, ...); + +#define cpt (cp->info+trust) + +%} + +%token STRING +%token SETUP_TIMESTAMP SETUP_VERSION VERSION INSTALL SOURCE SDESC LDESC TYPE +%token T_PREV T_CURR T_TEST T_UNKNOWN + +%% + +whole_file + : setup_headers packages + ; + +setup_headers + : setup_header setup_headers + | /* empty */ + ; + +setup_header + : SETUP_TIMESTAMP STRING '\n' { setup_timestamp = strtoul ($2, 0, 0); } + | SETUP_VERSION STRING '\n' { setup_version = strdup ($2); } + | '\n' + | error { yyerror ("unrecognized line in setup.ini headers (do you have the latest setup?)"); } '\n' + ; + +packages + : package packages + | /* empty */ + ; + +package + : '@' STRING '\n' { new_package($2); } + lines + ; + +lines + : simple_line '\n' lines + | simple_line + ; + +simple_line + : VERSION STRING { cpt->version = $2; } + | SDESC STRING { cp->sdesc = $2; } + | LDESC STRING { cp->ldesc = $2; } + | INSTALL STRING STRING { cpt->install = $2; + cpt->install_size = atoi($3); } + | SOURCE STRING STRING { cpt->source = $2; + cpt->source_size = atoi($3); } + | TYPE STRING { if (!strcmp ($2, "cygwin")) + cp->type = TY_CYGWIN; + else if (!strcmp ($2, "native")) + cp->type = TY_NATIVE; + else + cp->type = TY_GENERIC; } + | T_PREV { trust = TRUST_PREV; } + | T_CURR { trust = TRUST_CURR; } + | T_TEST { trust = TRUST_TEST; } + | T_UNKNOWN { trust = TRUST_UNKNOWN; } + | /* empty */ + | error '\n' { yylineno --; + yyerror ("unrecognized line in package %s (do you have the latest setup?)", cp->name); + yylineno ++; + } + ; + +%% + +Package *package = 0; +Package *xemacs_package = 0; +int npackages = 0; +static int maxpackages = 0; + +Package * +new_package (char *name) +{ + if (package == 0) + maxpackages = npackages = 0; + if (npackages >= maxpackages) + { + maxpackages += 10; + if (package) + package = (Package *) realloc (package, maxpackages * sizeof (Package)); + else + package = (Package *) malloc (maxpackages * sizeof (Package)); + } + cp = package + npackages; + npackages ++; + + memset (cp, 0, sizeof (Package)); + cp->name = name; + + trust = TRUST_CURR; + + return cp; +} diff --git a/netinstall/install.cc b/netinstall/install.cc new file mode 100644 index 0000000..5d64055 --- /dev/null +++ b/netinstall/install.cc @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to intall all the packages selected in + the install list (in ini.h). Note that we use a separate thread to + maintain the progress dialog, so we avoid the complexity of + handling two tasks in one thread. We also create or update all the + files in /etc/setup and create the mount points. */ + +#include +#include +#include +#ifndef WIN32_NATIVE +#include +#endif +#include +#include +#include +#include + +#include "win32.h" +#include "commctrl.h" + +#include "resource.h" +#include "ini.h" +#include "dialog.h" +#include "concat.h" +#include "geturl.h" +#include "mkdir.h" +#include "state.h" +#include "tar.h" +#include "diskfull.h" +#include "msg.h" +#include "regedit.h" +#include "reginfo.h" +#include "log.h" +#include "hash.h" + +#include "port.h" + +static HWND ins_dialog = 0; +static HWND ins_action = 0; +static HWND ins_pkgname = 0; +static HWND ins_filename = 0; +static HWND ins_pprogress = 0; +static HWND ins_iprogress = 0; +static HWND ins_diskfull = 0; +static HANDLE init_event; + +static int total_bytes = 0; +static int total_bytes_sofar = 0; +static int package_bytes = 0; + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + case IDCANCEL: + exit_setup (1); + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + ins_dialog = h; + ins_action = GetDlgItem (h, IDC_INS_ACTION); + ins_pkgname = GetDlgItem (h, IDC_INS_PKG); + ins_filename = GetDlgItem (h, IDC_INS_FILE); + ins_pprogress = GetDlgItem (h, IDC_INS_PPROGRESS); + ins_iprogress = GetDlgItem (h, IDC_INS_IPROGRESS); + ins_diskfull = GetDlgItem (h, IDC_INS_DISKFULL); + SetEvent (init_event); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +static DWORD WINAPI +dialog (void *) +{ + MSG m; + HWND new_dialog = CreateDialog (hinstance, MAKEINTRESOURCE (IDD_INSTATUS), + 0, dialog_proc); + if (new_dialog == 0) + fatal ("create dialog"); + ShowWindow (new_dialog, SW_SHOWNORMAL); + UpdateWindow (new_dialog); + while (GetMessage (&m, 0, 0, 0) > 0) { + TranslateMessage (&m); + DispatchMessage (&m); + } + return FALSE; +} + +static void +init_dialog () +{ + if (ins_dialog == 0) + { + DWORD tid; + HANDLE thread; + init_event = CreateEvent (0, 0, 0, 0); + thread = CreateThread (0, 0, dialog, 0, 0, &tid); + WaitForSingleObject (init_event, 10000); + CloseHandle (init_event); + SendMessage (ins_pprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100)); + SendMessage (ins_iprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100)); + SendMessage (ins_diskfull, PBM_SETRANGE, 0, MAKELPARAM (0, 100)); + } + + SetWindowText (ins_pkgname, ""); + SetWindowText (ins_filename, ""); + SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) 0, 0); + SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) 0, 0); + SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) 0, 0); + ShowWindow (ins_dialog, SW_SHOWNORMAL); + SetForegroundWindow (ins_dialog); +} + +static void +progress (int bytes) +{ + int perc; + + if (package_bytes > 100) + { + perc = bytes / (package_bytes / 100); + SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) perc, 0); + } + + if (total_bytes > 100) + { + perc = (total_bytes_sofar + bytes) / (total_bytes / 100); + SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) perc, 0); + } +} + +static void +badrename (char *o, char *n) +{ + char *err = strerror (errno); + if (!err) + err = "(unknown error)"; + note (IDS_ERR_RENAME, o, n, err); +} + +static char *standard_dirs[] = { + 0 +}; + +void +hash::add_subdirs (char *path) +{ + char *nonp, *pp; + for (nonp = path; *nonp == '\\' || *nonp == '/'; nonp++); + for (pp = path + strlen(path) - 1; pp>nonp; pp--) + if (*pp == '/' || *pp == '\\') + { + int i, s=0; + char c = *pp; + *pp = 0; + for (i=0; standard_dirs[i]; i++) + if (strcmp (standard_dirs[i]+1, path) == 0) + { + s = 1; + break; + } + if (s == 0) + add (path); + *pp = c; + } +} + +char * +map_filename (char *fn, int type) +{ + char *dest_file; + while (*fn == '/' || *fn == '\\') + fn++; + if (type == TY_GENERIC) + dest_file = concat (root_dir, XEMACS_PACKAGE_DIR, fn, 0); + else // TY_CYGWIN | TY_NATIVE + dest_file = concat (root_dir, "/", fn, 0); + return dest_file; +} + +static int +exists (char *file) +{ + if (_access (file, 0) == 0) + return 1; + return 0; +} + + +static int num_installs, num_uninstalls; + +static void +uninstall_one (char *name, int action, int type) +{ + hash dirs; + char line[_MAX_PATH]; + char* fname = (type == TY_GENERIC ? + concat (root_dir, XEMACS_PACKAGE_DIR, "pkginfo/MANIFEST.", + name, 0) : + concat (root_dir, XEMACS_SETUP_DIR, "MANIFEST.", name, 0)); + + FILE* lst = fopen (fname, "rb"); + + if (lst) + { + SetWindowText (ins_pkgname, name); + SetWindowText (ins_action, "Uninstalling..."); + if (action == ACTION_UPGRADE) + log (0, "Uninstalling old %s", name); + else + log (0, "Uninstalling %s", name); + + while (fgets (line, sizeof (line), lst)) + { + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = 0; + + dirs.add_subdirs (line); + + char *d = map_filename (line, type); + DWORD dw = GetFileAttributes (d); + if (dw != 0xffffffff && !(dw & FILE_ATTRIBUTE_DIRECTORY)) + { + log (LOG_BABBLE, "unlink %s", d); + DeleteFile (d); + } + } + fclose (lst); + + remove (fname); + + dirs.reverse_sort (); + char *subdir = 0; + while ((subdir = dirs.enumerate (subdir)) != 0) + { + char *d = map_filename (subdir, type); + if (RemoveDirectory (d)) + log (LOG_BABBLE, "rmdir %s", d); + } + num_uninstalls ++; + } +} + + +static int +install_one (char *name, char *file, int file_size, int action, int type) +{ + int errors = 0; + char *local = file, *cp, *fn, *base; + + base = local; + for (cp=local; *cp; cp++) + if (*cp == '/' || *cp == '\\' || *cp == ':') + base = cp+1; + SetWindowText (ins_pkgname, base); + + if (!exists (local) && exists (base)) + local = base; + if (!exists (local)) + { + note (IDS_ERR_OPEN_READ, local, "No such file"); + return 1; + } + + char* fname = (type == TY_GENERIC ? + concat (root_dir, XEMACS_PACKAGE_DIR, "pkginfo/MANIFEST.", + name, 0) : + concat (root_dir, XEMACS_SETUP_DIR, "MANIFEST.", name, 0)); + + FILE* lst = fopen (fname, "wb"); + + package_bytes = file_size; + + switch (action) + { + case ACTION_NEW: + SetWindowText (ins_action, "Installing..."); + break; + case ACTION_UPGRADE: + SetWindowText (ins_action, "Upgrading..."); + break; + } + + log (0, "Installing %s", local); + tar_open (local); + while ((fn = tar_next_file ())) + { + char *dest_file; + + if (lst) + fprintf (lst, "%s\n", fn); + + dest_file = map_filename (fn, type); + + SetWindowText (ins_filename, dest_file); + log (LOG_BABBLE, "Installing file %s", dest_file); + if (tar_read_file (dest_file) != 0) + { + log (0, "Unable to install file %s", dest_file); + errors ++; + } + + progress (tar_ftell ()); + num_installs ++; + } + tar_close (); + + total_bytes_sofar += file_size; + progress (0); + + int df = diskfull (root_dir); + SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0); + + if (lst) + fclose (lst); + + return errors; +} + +void +do_install (HINSTANCE h) +{ + int i; + int errors = 0; + + num_installs = 0, num_uninstalls = 0; + + next_dialog = IDD_DESKTOP; + + mkdir_p (1, root_dir); + + for (i=0; standard_dirs[i]; i++) + { + char *p = concat (root_dir, standard_dirs[i], 0); + mkdir_p (1, p); + free (p); + } + + dismiss_url_status_dialog (); + + init_dialog (); + + total_bytes = 0; + total_bytes_sofar = 0; + + int df = diskfull (root_dir); + SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0); + + LOOP_PACKAGES + { + total_bytes += pi.install_size; + } + + for (i=0; i + * based on work and suggestions of DJ Delorie + * + */ + +/* The purpose of this file is to ask the user where they want the + root of the installation to be, and to ask whether the user prefers + text or binary mounts. */ + +#include "win32.h" +#include +#include +#include +#include + +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "msg.h" +#include "concat.h" +#include "log.h" + +static void +check_if_enable_next (HWND h) +{ + EnableWindow (GetDlgItem (h, IDOK), local_dir != 0); +} + +static void +load_dialog (HWND h) +{ + eset (h, IDC_LOCAL_DIR, local_dir); + check_if_enable_next (h); +} + +static void +save_dialog (HWND h) +{ + local_dir = eget (h, IDC_LOCAL_DIR, local_dir); +} + + +static int CALLBACK +browse_cb (HWND h, UINT m, LPARAM lp, LPARAM data) +{ + switch (m) + { + case BFFM_INITIALIZED: + if (local_dir) + SendMessage (h, BFFM_SETSELECTION, TRUE, (LPARAM)local_dir); + break; + } + return 0; +} + +static void +browse (HWND h) +{ + BROWSEINFO bi; + CHAR name[MAX_PATH]; + LPITEMIDLIST pidl; + memset (&bi, 0, sizeof (bi)); + bi.hwndOwner = h; + bi.pszDisplayName = name; + bi.lpszTitle = "Select download directory"; + bi.ulFlags = BIF_RETURNONLYFSDIRS; + bi.lpfn = browse_cb; + pidl = SHBrowseForFolder (&bi); + if (pidl) + { + if (SHGetPathFromIDList (pidl, name)) + eset (h, IDC_LOCAL_DIR, name); + } +} + + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_LOCAL_DIR: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDC_LOCAL_DIR_BROWSE: + browse (h); + break; + + case IDOK: + save_dialog (h); + if (SetCurrentDirectoryA (local_dir)) + { + switch (source) + { + case IDC_SOURCE_DOWNLOAD: + NEXT (IDD_NET); + break; + case IDC_SOURCE_NETINST: + case IDC_SOURCE_CWD: + NEXT (IDD_ROOT); + break; + default: + NEXT (0); + break; + } + } + else + note (IDS_ERR_CHDIR, local_dir); + + break; + + case IDC_BACK: + save_dialog (h); + NEXT (IDD_SOURCE); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +extern char cwd[_MAX_PATH]; + +void +do_local_dir (HINSTANCE h) +{ + int rv = 0; + rv = DialogBox (h, MAKEINTRESOURCE (IDD_LOCAL_DIR), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); + + log (0, "Selected local directory: %s", local_dir); +} + diff --git a/netinstall/log.cc b/netinstall/log.cc new file mode 100644 index 0000000..0ffc8e5 --- /dev/null +++ b/netinstall/log.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to centralize all the logging functions. */ + +#include "win32.h" +#include +#include +#include +#include + +#include "resource.h" +#include "msg.h" +#include "log.h" +#include "dialog.h" +#include "state.h" +#include "concat.h" +#include "mkdir.h" + +struct LogEnt { + LogEnt *next; + int flags; + time_t when; + char msg[1]; +}; + +static LogEnt *first_logent = 0; +static LogEnt **next_logent = &first_logent; + +void +log (int flags, char *fmt, ...) +{ + char buf[1000]; + va_list args; + va_start (args, fmt); + vsprintf (buf, fmt, args); + + LogEnt *l = (LogEnt *) malloc (sizeof (LogEnt) + strlen (buf) + 20); + l->next = 0; + l->flags = flags; + time (&(l->when)); + *next_logent = l; + next_logent = &(l->next); + + char *b = l->msg; + if (flags & LOG_TIMESTAMP) + { + struct tm *tm = localtime (&(l->when)); + strftime (b, 1000, "%Y/%m/%d %H:%M:%S ", tm); + b += strlen (b); + } + + strcpy (b, buf); + msg ("LOG: %d %s", l->flags, l->msg); +} + +void +log_save (int babble, char *filename, int append) +{ + static int been_here = 0; + if (been_here) + return; + been_here = 1; + + mkdir_p (0, filename); + + FILE *f = fopen (filename, append ? "at" : "wt"); + if (!f) + { + fatal (IDS_NOLOGFILE, filename); + return; + } + + LogEnt *l; + + for (l=first_logent; l; l=l->next) + { + if (babble || !(l->flags & LOG_BABBLE)) + { + fputs (l->msg, f); + if (l->msg[strlen(l->msg)-1] != '\n') + fputc ('\n', f); + } + } + + fclose (f); + been_here = 0; +} + +void +exit_setup (int exit_code) +{ + static int been_here = 0; + if (been_here) + ExitProcess (1); + been_here = 1; + + if (exit_msg) + note (exit_msg); + + log (LOG_TIMESTAMP, "Ending cygwin install"); + + if (source == IDC_SOURCE_DOWNLOAD || !root_dir) + { + log_save (LOG_BABBLE, "setup.log.full", 0); + log_save (0, "setup.log", 1); + } + else + { + log_save (LOG_BABBLE, concat (root_dir, "/setup.log.full", 0), 0); + log_save (0, concat (root_dir, "/setup.log", 0), 1); + } + + ExitProcess (exit_code); +} diff --git a/netinstall/log.h b/netinstall/log.h new file mode 100644 index 0000000..40c4b9d --- /dev/null +++ b/netinstall/log.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* This is for "printf"-like logging. Messages are stored in memory + until they're written out. "babble" means the message is just idle + babbling; it can be ignored for shorter logs. */ + +#define LOG_BABBLE 1 +#define LOG_TIMESTAMP 2 + +void log (int flags, char *fmt, ...); + +/* Here, "babble" means to write out the babble also. If "append" is + nonzero, the log is appended to any existing file. */ + +void log_save (int babble, char *filename, int append); + +/* This is the only legal way to exit. It writes out all the logs and things */ + +void exit_setup (int exit_code); diff --git a/netinstall/main.cc b/netinstall/main.cc new file mode 100644 index 0000000..4a93fb2 --- /dev/null +++ b/netinstall/main.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* OK, here's how this works. Each of the steps needed for install - + dialogs, downloads, installs - are in their own files and have some + "do_*" function (prototype in dialog.h) and a resource id (IDD_* or + IDD_S_* in resource.h) for that step. Each step is responsible for + selecting the next step! See the NEXT macro in dialog.h. Note + that the IDD_S_* ids are fake; those are for steps that don't + really have a controlling dialog (some have progress dialogs, but + those don't count, although they could). Replace the IDD_S_* with + IDD_* if you create a real dialog for those steps. */ + +#include "win32.h" + +#include +#include +#include "resource.h" +#include "dialog.h" +#include "state.h" +#include "msg.h" +#include "netio.h" +#include "find.h" +#include "log.h" + +#include "port.h" + +void netio_test (char *); + +int next_dialog; +int exit_msg = 0; + +HINSTANCE hinstance; + +int WINAPI +WinMain (HINSTANCE h, + HINSTANCE hPrevInstance, + LPSTR command_line, + int cmd_show) +{ + hinstance = h; + + next_dialog = IDD_SPLASH; + + log (LOG_TIMESTAMP, "Starting XEmacs install"); + + char cwd[_MAX_PATH]; + GetCurrentDirectory (sizeof (cwd), cwd); + local_dir = strdup (cwd); + log (0, "Current Directory: %s", cwd); + + while (next_dialog) + { + switch (next_dialog) + { + case IDD_SPLASH: do_splash (h); break; + case IDD_SOURCE: do_source (h); break; + case IDD_LOCAL_DIR: do_local_dir (h); break; + case IDD_ROOT: do_root (h); break; + case IDD_NET: do_net (h); break; + case IDD_SITE: do_site (h); break; + case IDD_OTHER_URL: do_other (h); break; + case IDD_S_LOAD_INI: do_ini (h); break; + case IDD_S_FROM_CWD: do_fromcwd (h); break; + case IDD_CHOOSE: do_choose (h); break; + case IDD_S_DOWNLOAD: do_download (h); break; + case IDD_S_INSTALL: do_install (h); break; + case IDD_DESKTOP: do_desktop (h); break; + case IDD_S_POSTINSTALL: do_postinstall (h); break; + + default: + next_dialog = 0; + break; + } + } + + exit_setup (0); + + return EXIT_SUCCESS; +} diff --git a/netinstall/mkdir.cc b/netinstall/mkdir.cc new file mode 100644 index 0000000..ab62f9e --- /dev/null +++ b/netinstall/mkdir.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* see mkdir.h */ + +#include "win32.h" +#include +#include "mkdir.h" + +int +mkdir_p (int isadir, char *path) +{ + char saved_char, *slash = 0; + char *c; + DWORD d, gse; + + d = GetFileAttributes (path); + if (d != 0xffffffff && d & FILE_ATTRIBUTE_DIRECTORY) + return 0; + + if (isadir) + { + if (CreateDirectory (path, 0)) + return 0; + gse = GetLastError (); + if (gse != ERROR_PATH_NOT_FOUND && gse != ERROR_FILE_NOT_FOUND) + { + if (gse == ERROR_ALREADY_EXISTS) + { + fprintf (stderr, "warning: deleting \"%s\" so I can make a directory there\n", + path); + if (DeleteFileA (path)) + return mkdir_p (isadir, path); + } + return 1; + } + } + + for (c=path; *c; c++) + { + if (*c == ':') + slash = 0; + if (*c == '/' || *c == '\\') + slash = c; + } + + if (!slash) + return 0; + + saved_char = *slash; + *slash = 0; + if (mkdir_p (1, path)) + { + *slash = saved_char; + return 1; + } + *slash = saved_char; + + if (!isadir) + return 0; + + return mkdir_p (isadir, path); +} diff --git a/netinstall/mkdir.h b/netinstall/mkdir.h new file mode 100644 index 0000000..151edc0 --- /dev/null +++ b/netinstall/mkdir.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Create a directory, and any needed parent directories. If "isadir" + is non-zero, "path" is the name of a directory. If "isadir" is + zero, "path" is the name of a *file* that we need a directory + for. */ + +extern int mkdir_p (int isadir, char *path); diff --git a/netinstall/mklink2.c b/netinstall/mklink2.c new file mode 100644 index 0000000..deed33d --- /dev/null +++ b/netinstall/mklink2.c @@ -0,0 +1,27 @@ +#include "win32.h" +#include "shlobj.h" + +/* This part of the code must be in C because the C++ interface to COM +doesn't work. */ + +void +make_link_2 (char *exepath, char *args, char *icon, char *lname) +{ + IShellLink *sl; + IPersistFile *pf; + WCHAR widepath [_MAX_PATH]; + + CoCreateInstance (&CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID *) & sl); + sl->lpVtbl->QueryInterface (sl, &IID_IPersistFile, (void **) &pf); + + sl->lpVtbl->SetPath (sl, exepath); + sl->lpVtbl->SetArguments (sl, args); + sl->lpVtbl->SetIconLocation (sl, icon, 0); + + MultiByteToWideChar (CP_ACP, 0, lname, -1, widepath, _MAX_PATH); + pf->lpVtbl->Save (pf, widepath, TRUE); + + pf->lpVtbl->Release (pf); + sl->lpVtbl->Release (sl); +} diff --git a/netinstall/msg.cc b/netinstall/msg.cc new file mode 100644 index 0000000..5a9ed24 --- /dev/null +++ b/netinstall/msg.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to centralize all the message + functions. */ + +static char *cvsid = "\n%%% $Id: msg.cc,v 1.1.2.1 2000/12/11 22:01:36 andyp Exp $\n"; + +#include "win32.h" +#include +#include +#include "dialog.h" +#include "log.h" + +void +msg (char *fmt, ...) +{ + char buf[1000]; + va_list args; + va_start (args, fmt); + vsprintf (buf, fmt, args); + OutputDebugString (buf); +} + +static int +mbox (char *name, int type, int id, va_list args) +{ + char buf[1000], fmt[1000]; + + if (LoadString (hinstance, id, fmt, sizeof (fmt)) <= 0) + ExitProcess (0); + + vsprintf (buf, fmt, args); + log (0, "mbox %s: %s", name, buf); + return MessageBox (0, buf, "XEmacs Setup", type | MB_TOPMOST); +} + +void +note (int id, ...) +{ + va_list args; + va_start (args, id); + mbox ("note", 0, id, args); +} + +void +fatal (int id, ...) +{ + va_list args; + va_start (args, id); + mbox ("fatal", 0, id, args); + exit_setup (1); +} + +int +yesno (int id, ...) +{ + va_list args; + va_start (args, id); + return mbox ("yesno", MB_YESNO, id, args); +} diff --git a/netinstall/msg.h b/netinstall/msg.h new file mode 100644 index 0000000..ddd3785 --- /dev/null +++ b/netinstall/msg.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* This is for "printf"-like debugging. Messages go to + OutputDebugString, which can be seen while debugging under GDB or + via a debug message monitor. */ + +void msg(char *fmt, ...); + +/* This pops up a dialog with text from the string table ("id"), which + is interpreted like printf. The program exits when the user + presses OK. */ + +void fatal (int id, ...); + +/* Similar, but the program continues when the user presses OK */ + +void note (int id, ...); + +/* returns IDYES or IDNO, otherwise same as note() */ +int yesno (int id, ...); diff --git a/netinstall/net.cc b/netinstall/net.cc new file mode 100644 index 0000000..3891d3f --- /dev/null +++ b/netinstall/net.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to get the network configuration + information from the user. */ + +#include "win32.h" +#include +#include +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "msg.h" +#include "log.h" + +static int rb[] = { IDC_NET_IE5, IDC_NET_DIRECT, IDC_NET_PROXY, 0 }; + +static void +check_if_enable_next (HWND h) +{ + int e = 0, p = 0, pu = 0; + if (net_method == IDC_NET_IE5) + pu = 1; + if (net_method == IDC_NET_IE5 || net_method == IDC_NET_DIRECT) + e = 1; + else if (net_method == IDC_NET_PROXY) + { + p = pu = 1; + if (net_proxy_host && net_proxy_port) + e = 1; + } + EnableWindow (GetDlgItem (h, IDOK), e); + EnableWindow (GetDlgItem (h, IDC_PROXY_HOST), p); + EnableWindow (GetDlgItem (h, IDC_PROXY_PORT), p); +} + +static void +load_dialog (HWND h) +{ + rbset (h, rb, net_method); + eset (h, IDC_PROXY_HOST, net_proxy_host); + if (net_proxy_port == 0) + net_proxy_port = 80; + eset (h, IDC_PROXY_PORT, net_proxy_port); + check_if_enable_next (h); +} + +static void +save_dialog (HWND h) +{ + net_method = rbget (h, rb); + net_proxy_host = eget (h, IDC_PROXY_HOST, net_proxy_host); + net_proxy_port = eget (h, IDC_PROXY_PORT); +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_NET_IE5: + case IDC_NET_DIRECT: + case IDC_NET_PROXY: + case IDC_PROXY_HOST: + case IDC_PROXY_PORT: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDOK: + save_dialog (h); + switch (source) + { + case IDC_SOURCE_NETINST: + case IDC_SOURCE_DOWNLOAD: + NEXT (IDD_SITE); + break; + case IDC_SOURCE_CWD: + NEXT (0); + break; + default: + msg ("source is default? %d\n", source); + NEXT (0); + } + break; + + case IDC_BACK: + save_dialog (h); + switch (source) + { + case IDC_SOURCE_DOWNLOAD: + NEXT (IDD_LOCAL_DIR); + break; + case IDC_SOURCE_NETINST: + case IDC_SOURCE_CWD: + NEXT (IDD_ROOT); + break; + } + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +void +do_net (HINSTANCE h) +{ + int rv = 0; + + rv = DialogBox (h, MAKEINTRESOURCE (IDD_NET), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); + + log (0, "net: %s", + (net_method == IDC_NET_IE5) ? "IE5" : + (net_method == IDC_NET_DIRECT) ? "Direct" : "Proxy"); +} + diff --git a/netinstall/netio.cc b/netinstall/netio.cc new file mode 100644 index 0000000..5d04d93 --- /dev/null +++ b/netinstall/netio.cc @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to coordinate the various access + methods known to setup. To add a new method, create a pair of + nio-*.[ch] files and add the logic to NetIO::open here */ + +#include "win32.h" +#include +#include +#include + +#include "resource.h" +#include "state.h" +#include "msg.h" +#include "netio.h" +#include "nio-file.h" +#include "nio-ie5.h" +#include "nio-http.h" +#include "nio-ftp.h" +#include "dialog.h" +#include "log.h" + +#include "port.h" + +NetIO::NetIO (char *Purl) +{ + set_url (Purl); +} + +NetIO::~NetIO () +{ + if (url) + free (url); + if (proto) + free (proto); + if (host) + free (host); + if (path) + free (path); +} + +void +NetIO::set_url (char *Purl) +{ + char *bp, *ep, c; + + file_size = 0; + url = _strdup (Purl); + proto = 0; + host = 0; + port = 0; + path = 0; + + bp = url; + ep = strstr (bp, "://"); + if (!ep) + { + path = url; + return; + } + + *ep = 0; + proto = _strdup (bp); + *ep = ':'; + bp = ep+3; + + ep = bp + strcspn (bp, ":/"); + c = *ep; + *ep = 0; + host = _strdup (bp); + *ep = c; + + if (*ep == ':') + { + port = atoi (ep+1); + ep = strchr (ep, '/'); + } + + if (*ep) + path = _strdup (ep); +} + +int +NetIO::ok () +{ + return 0; +} + +int +NetIO::read (char *buf, int nbytes) +{ + return 0; +} + +NetIO * +NetIO::open (char *url) +{ + NetIO *rv = 0; + enum {http, ftp, file} proto; + if (strncmp (url, "http://", 7) == 0) + proto = http; + else if (strncmp (url, "ftp://", 6) == 0) + proto = ftp; + else + proto = file; + + if (proto == file) + rv = new NetIO_File (url); + else if (net_method == IDC_NET_IE5) + rv = new NetIO_IE5 (url); + else if (net_method == IDC_NET_PROXY) + rv = new NetIO_HTTP (url); + else if (net_method == IDC_NET_DIRECT) + { + switch (proto) + { + case http: + rv = new NetIO_HTTP (url); + break; + case ftp: + rv = new NetIO_FTP (url); + break; + } + } + + if (!rv->ok ()) + { + delete rv; + return 0; + } + + return rv; +} + + +static char **user, **passwd; +static int loading = 0; + +static void +check_if_enable_ok (HWND h) +{ + int e = 0; + if (*user && *passwd) + e = 1; + EnableWindow (GetDlgItem (h, IDOK), e); +} + +static void +load_dialog (HWND h) +{ + loading = 1; + eset (h, IDC_NET_USER, *user); + eset (h, IDC_NET_PASSWD, *passwd); + check_if_enable_ok (h); + loading = 0; +} + +static void +save_dialog (HWND h) +{ + *user = eget (h, IDC_NET_USER, *user); + *passwd = eget (h, IDC_NET_PASSWD, *passwd); +} + +static BOOL +auth_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_NET_USER: + case IDC_NET_PASSWD: + if (code == EN_CHANGE && !loading) + { + save_dialog (h); + check_if_enable_ok (h); + } + break; + + case IDOK: + save_dialog (h); + EndDialog (h, 0); + break; + + case IDCANCEL: + EndDialog (h, 1); + exit_setup (1); + break; + } + return FALSE; +} + +static BOOL CALLBACK +auth_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, auth_cmd); + } + return FALSE; +} + +static int +auth_common (HINSTANCE h, int id) +{ + return DialogBox (h, MAKEINTRESOURCE (id), 0, auth_proc); +} + +int +NetIO::get_auth () +{ + user = &net_user; + passwd = &net_passwd; + return auth_common (hinstance, IDD_NET_AUTH); +} + +int +NetIO::get_proxy_auth () +{ + user = &net_proxy_user; + passwd = &net_proxy_passwd; + return auth_common (hinstance, IDD_PROXY_AUTH); +} diff --git a/netinstall/netio.h b/netinstall/netio.h new file mode 100644 index 0000000..b0a91ca --- /dev/null +++ b/netinstall/netio.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* This is the parent class for all the access methods known to setup + (i.e. ways to download files from the internet or other sources */ + +class NetIO { +protected: + NetIO (char *url); + void set_url (char *url); + +public: + /* if nonzero, this is the estimated total file size */ + int file_size; + /* broken down url FYI */ + char *url; + char *proto; + char *host; + int port; + char *path; + virtual ~NetIO (); + + /* The user calls this function to create a suitable accessor for + the given URL. It uses the network setup state in state.h. If + anything fails, either the return values is NULL or the returned + object is !ok() */ + static NetIO * open (char *url); + + /* If !ok() that means the transfer isn't happening. */ + virtual int ok (); + + /* Read `nbytes' bytes from the file. Returns zero when the file + is complete. */ + virtual int read (char *buf, int nbytes); + + /* Helper functions for http/ftp protocols. Both return nonzero for + "cancel", zero for "ok". They set net_proxy_user, etc, in + state.h */ + int get_auth (); + int get_proxy_auth (); +}; diff --git a/netinstall/nio-file.cc b/netinstall/nio-file.cc new file mode 100644 index 0000000..57e061d --- /dev/null +++ b/netinstall/nio-file.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to manage access to files stored on the + local disk (i.e. "downloading" setup.ini). Called from netio.cc */ + +#include +#include +#include +#include +#include "win32.h" +#include "netio.h" +#include "nio-file.h" +#include "resource.h" +#include "msg.h" + +NetIO_File::NetIO_File (char *Purl) + : NetIO (Purl) +{ + struct stat s; + fd = fopen (path, "rb"); + if (fd) + { + stat (path, &s); + file_size = s.st_size; + } + else + { + char *err = strerror (errno); + if (!err) + err = "(unknown error)"; + note (IDS_ERR_OPEN_READ, path, err); + } +} + +NetIO_File::~NetIO_File () +{ + if (fd) + fclose ((FILE *)fd); +} + +int +NetIO_File::ok () +{ + return fd ? 1 : 0; +} + +int +NetIO_File::read (char *buf, int nbytes) +{ + return fread (buf, 1, nbytes, (FILE *)fd); +} diff --git a/netinstall/nio-file.h b/netinstall/nio-file.h new file mode 100644 index 0000000..6d2eb92 --- /dev/null +++ b/netinstall/nio-file.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* see nio-file.cc */ + +class NetIO_File : public NetIO { +public: + NetIO_File (char *url); + void *fd; + ~NetIO_File (); + virtual int ok (); + virtual int read (char *buf, int nbytes); +}; diff --git a/netinstall/nio-ftp.cc b/netinstall/nio-ftp.cc new file mode 100644 index 0000000..f30beb6 --- /dev/null +++ b/netinstall/nio-ftp.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* This file is responsible for implementing all direct FTP protocol + channels. It is intentionally simplistic. */ + +#include "win32.h" +#include "winsock.h" +#include +#include +#include + +#include "resource.h" +#include "state.h" +#include "simpsock.h" +#include "log.h" + +#include "netio.h" +#include "nio-ftp.h" + +static SimpleSocket *cmd = 0; +static char *cmd_host = 0; +static int cmd_port = 0; + +static char *last_line; + +static int +ftp_line (SimpleSocket *s) +{ + do { + last_line = s->gets (); + log (LOG_BABBLE, "ftp > %s", last_line); + } while (last_line && (!isdigit (last_line[0]) || last_line[3] != ' ')); + return atoi (last_line ? last_line : "0"); +} + +NetIO_FTP::NetIO_FTP (char *Purl) + : NetIO (Purl) +{ + s = 0; + int code; + + if (port == 0) + port = 21; + + if (cmd_host && strcmp (host, cmd_host) != 0 || port != cmd_port) + { + if (cmd) + cmd->printf ("QUIT\r\n"); + delete cmd; + free (cmd_host); + cmd = 0; + cmd_host = 0; + } + + if (cmd == 0) + { + SimpleSocket *c = new SimpleSocket (host, port); + code = ftp_line (c); + c->printf ("USER anonymous\r\n"); + code = ftp_line (c); + if (code == 331) + { + c->printf ("PASS cygwin-setup@\r\n"); + code = ftp_line (c); + } + + if (code < 200 || code >= 300) + { + delete c; + return; + } + + cmd = c; + cmd_host = _strdup (host); + cmd_port = port; + + cmd->printf ("TYPE I\r\n"); + code = ftp_line (cmd); + } + + cmd->printf ("PASV\r\n"); + do { + code = ftp_line (cmd); + } while (code == 226); /* previous RETR */ + if (code != 227) + return; + + char *paren = strchr (last_line, '('); + if (!paren) + return; + + int i1, i2, i3, i4, p1, p2; + sscanf (paren+1, "%d,%d,%d,%d,%d,%d", &i1, &i2, &i3, &i4, &p1, &p2); + char tmp[20]; + sprintf (tmp, "%d.%d.%d.%d", i1, i2, i3, i4); + s = new SimpleSocket (tmp, p1*256 + p2); + + cmd->printf ("RETR %s\r\n", path); + code = ftp_line (cmd); + if (code != 150) + { + delete s; + s = 0; + return; + } +} + +NetIO_FTP::~NetIO_FTP () +{ + if (s) + delete s; +} + +int +NetIO_FTP::ok () +{ + if (s) + return 1; + return 0; +} + +int +NetIO_FTP::read (char *buf, int nbytes) +{ + if (!s) + return 0; + return s->read (buf, nbytes); +} diff --git a/netinstall/nio-ftp.h b/netinstall/nio-ftp.h new file mode 100644 index 0000000..4548bcd --- /dev/null +++ b/netinstall/nio-ftp.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Direct FTP (without proxy) */ + +class SimpleSocket; + +class NetIO_FTP : public NetIO { + SimpleSocket *s; + +public: + NetIO_FTP (char *url); + virtual ~NetIO_FTP (); + + /* If !ok() that means the transfer isn't happening. */ + virtual int ok (); + + /* Read `nbytes' bytes from the file. Returns zero when the file + is complete. */ + virtual int read (char *buf, int nbytes); +}; diff --git a/netinstall/nio-http.cc b/netinstall/nio-http.cc new file mode 100644 index 0000000..fa5210a --- /dev/null +++ b/netinstall/nio-http.cc @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* This file is responsible for implementing all direct HTTP protocol + channels. It is intentionally simplistic. */ + +#include "win32.h" +#include "winsock.h" +#include +#include + +#include "resource.h" +#include "state.h" +#include "simpsock.h" +#include "msg.h" + +#include "netio.h" +#include "nio-http.h" + +static char six2pr[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/' +}; + +static char * +base64_encode (char *username, char *password) +{ + unsigned char *ep; + char *rp; + static char *rv = 0; + if (rv) + free (rv); + rv = (char *) malloc (2 * (strlen (username) + strlen (password)) + 5); + + char *up = (char *) malloc (strlen (username) + strlen (password) + 6); + strcpy (up, username); + strcat (up, ":"); + strcat (up, password); + ep = (unsigned char *)up + strlen (up); + *ep++ = 0; + *ep++ = 0; + *ep++ = 0; + + char block[4]; + + rp = rv; + + for (ep = (unsigned char *)up; *ep; ep += 3) + { + block[0] = six2pr[ep[0] >> 2]; + block[1] = six2pr[((ep[0] << 4) & 0x30) | ((ep[1] >> 4) & 0x0f)]; + block[2] = six2pr[((ep[1] << 2) & 0x3c) | ((ep[2] >> 6) & 0x03)]; + block[3] = six2pr[ep[2] & 0x3f]; + + if (ep[1] == 0) + block[2] = block[3] = '='; + if (ep[2] == 0) + block[3] = '='; + memcpy (rp, block, 4); + rp += 4; + } + *rp = 0; + + free (up); + + return rv; +} + +NetIO_HTTP::NetIO_HTTP (char *Purl) + : NetIO (Purl) +{ + retry_get: + if (port == 0) + port = 80; + + if (net_method == IDC_NET_PROXY) + s = new SimpleSocket (net_proxy_host, net_proxy_port); + else + s = new SimpleSocket (host, port); + + if (!s->ok()) + { + s = 0; + return; + } + + if (net_method == IDC_NET_PROXY) + s->printf ("GET %s HTTP/1.0\r\n", url); + else + s->printf ("GET %s HTTP/1.0\r\n", path); + s->printf ("Host: %s:%d\r\n", host, port); + + if (net_user && net_passwd) + s->printf ("Authorization: Basic %s\r\n", + base64_encode (net_user, net_passwd)); + + if (net_proxy_user && net_proxy_passwd) + s->printf ("Proxy-Authorization: Basic %s\r\n", + base64_encode (net_proxy_user, net_proxy_passwd)); + + s->printf ("\r\n"); + + char *l = s->gets (); + int code; + sscanf (l, "%*s %d", &code); + if (code >= 300 && code < 400) + { + do { + l = s->gets (); + if (_strnicmp (l, "Location:", 9) == 0) + { + char *u = l + 9; + while (*u == ' ' || *u == '\t') + u++; + set_url (u); + delete s; + goto retry_get; + } + } while (*l); + } + if (code == 401) /* authorization required */ + { + get_auth (); + delete s; + goto retry_get; + } + if (code == 407) /* proxy authorization required */ + { + get_proxy_auth (); + delete s; + goto retry_get; + } + if (code >= 300) + { + delete s; + s = 0; + return; + } + do { + l = s->gets (); + if (_strnicmp (l, "Content-Length:", 15) == 0) + sscanf (l, "%*s %d", &file_size); + } while (*l); +} + +NetIO_HTTP::~NetIO_HTTP () +{ + if (s) + delete s; +} + +int +NetIO_HTTP::ok () +{ + if (s) + return 1; + return 0; +} + +int +NetIO_HTTP::read (char *buf, int nbytes) +{ + return s->read (buf, nbytes); +} diff --git a/netinstall/nio-http.h b/netinstall/nio-http.h new file mode 100644 index 0000000..e634299 --- /dev/null +++ b/netinstall/nio-http.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Direct HTTP (with or without proxy) */ + +class SimpleSocket; + +class NetIO_HTTP : public NetIO { + SimpleSocket *s; + +public: + NetIO_HTTP (char *url); + virtual ~NetIO_HTTP (); + + /* If !ok() that means the transfer isn't happening. */ + virtual int ok (); + + /* Read `nbytes' bytes from the file. Returns zero when the file + is complete. */ + virtual int read (char *buf, int nbytes); +}; diff --git a/netinstall/nio-ie5.cc b/netinstall/nio-ie5.cc new file mode 100644 index 0000000..9f2cae0 --- /dev/null +++ b/netinstall/nio-ie5.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to manage internet downloads using the + Internet Explorer version 5 DLLs. To use this method, the user + must already have installed and configured IE5. This module is + called from netio.cc, which is called from geturl.cc */ + +static char *cvsid = "\n%%% $Id: nio-ie5.cc,v 1.1.2.1 2000/12/11 22:01:41 andyp Exp $\n"; + +#include "win32.h" + +#include "resource.h" +#include "state.h" +#include "dialog.h" +#include "msg.h" +#include "netio.h" +#include "nio-ie5.h" + +static HINTERNET internet = 0; + +NetIO_IE5::NetIO_IE5 (char *_url) + : NetIO (_url) +{ + int resend = 0; + + if (internet == 0) + { + HINSTANCE h = LoadLibrary ("wininet.dll"); + if (!h) + { + note (IDS_WININET); + connection = 0; + return; + } + InternetAttemptConnect (0); + internet = InternetOpen ("Cygwin Setup", INTERNET_OPEN_TYPE_PRECONFIG, + NULL, NULL, 0); + } + + DWORD flags = + INTERNET_FLAG_DONT_CACHE | + INTERNET_FLAG_KEEP_CONNECTION | + INTERNET_FLAG_PRAGMA_NOCACHE | + INTERNET_FLAG_RELOAD | + INTERNET_FLAG_EXISTING_CONNECT | + INTERNET_FLAG_PASSIVE; + + connection = InternetOpenUrl (internet, url, NULL, 0, flags, 0); + + try_again: + + if (net_user && net_passwd) + { + InternetSetOption (connection, INTERNET_OPTION_USERNAME, + net_user, strlen (net_user)); + InternetSetOption (connection, INTERNET_OPTION_PASSWORD, + net_passwd, strlen (net_passwd)); + } + + if (net_proxy_user && net_proxy_passwd) + { + InternetSetOption (connection, INTERNET_OPTION_PROXY_USERNAME, + net_proxy_user, strlen (net_proxy_user)); + InternetSetOption (connection, INTERNET_OPTION_PROXY_PASSWORD, + net_proxy_passwd, strlen (net_proxy_passwd)); + } + + if (resend) + if (!HttpSendRequest (connection, 0, 0, 0, 0)) + connection = 0; + + if (!connection) + { + if (GetLastError () == ERROR_INTERNET_EXTENDED_ERROR) + { + char buf[2000]; + DWORD e, l=sizeof (buf); + InternetGetLastResponseInfo (&e, buf, &l); + MessageBox (0, buf, "Internet Error", 0); + } + } + + DWORD type, type_s; + type_s = sizeof (type); + InternetQueryOption (connection, INTERNET_OPTION_HANDLE_TYPE, + &type, &type_s); + + switch (type) + { + case INTERNET_HANDLE_TYPE_HTTP_REQUEST: + case INTERNET_HANDLE_TYPE_CONNECT_HTTP: + type_s = sizeof (DWORD); + if (HttpQueryInfo (connection, + HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, + &type, &type_s, NULL)) + { + if (type == 401) /* authorization required */ + { + flush_io(); + get_auth (); + resend = 1; + goto try_again; + } + else if (type == 407) /* proxy authorization required */ + { + flush_io(); + get_proxy_auth (); + resend = 1; + goto try_again; + } + else if (type >= 300) + { + connection = 0; + return; + } + } + } +} + +void +NetIO_IE5::flush_io () +{ + DWORD actual = 0; + char buf[1024]; + do { + InternetReadFile (connection, buf, 1024, &actual); + } while (actual > 0); +} + +NetIO_IE5::~NetIO_IE5 () +{ + if (connection) + InternetCloseHandle (connection); +} + +int +NetIO_IE5::ok () +{ + return (connection == NULL) ? 0 : 1; +} + +int +NetIO_IE5::read (char *buf, int nbytes) +{ + DWORD actual; + if (InternetReadFile (connection, buf, nbytes, &actual)) + return actual; + return -1; +} diff --git a/netinstall/nio-ie5.h b/netinstall/nio-ie5.h new file mode 100644 index 0000000..4cc71d5 --- /dev/null +++ b/netinstall/nio-ie5.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* see nio-ie5.cc */ + +class NetIO_IE5 : public NetIO { + HINTERNET connection; +public: + NetIO_IE5 (char *url); + ~NetIO_IE5 (); + virtual int ok (); + virtual int read (char *buf, int nbytes); + void flush_io(); +}; diff --git a/netinstall/other.cc b/netinstall/other.cc new file mode 100644 index 0000000..a701281 --- /dev/null +++ b/netinstall/other.cc @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* This handles the "other URL" option from the mirror site + selection. */ + +#include "win32.h" +#include +#include +#include +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "msg.h" +#include "log.h" + +/* private shared function, from site.cc */ +void save_site_url (void); + +static void +check_if_enable_next (HWND h) +{ + EnableWindow (GetDlgItem (h, IDOK), other_url ? 1 : 0); +} + +static void +load_dialog (HWND h) +{ + eset (h, IDC_OTHER_URL, other_url); + check_if_enable_next (h); +} + +static void +save_dialog (HWND h) +{ + other_url = eget (h, IDC_OTHER_URL, other_url); +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_OTHER_URL: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDOK: + save_dialog (h); + save_site_url (); + NEXT (IDD_S_LOAD_INI); + break; + + case IDC_BACK: + save_dialog (h); + NEXT (IDD_SITE); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +void +do_other (HINSTANCE h) +{ + int rv = 0; + rv = DialogBox (h, MAKEINTRESOURCE (IDD_OTHER_URL), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); + + log (0, "site: %s", other_url); +} + diff --git a/netinstall/port.h b/netinstall/port.h new file mode 100644 index 0000000..c2c019a --- /dev/null +++ b/netinstall/port.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* I prefer building a cygwin version of setup for debugging, as I + find that gdb can debug those programs (and the exceptions they + cause) better. This file handles the slight differences between + cygwin and mingw. */ + +#if defined(__CYGWIN__) || defined (__CYGWIN32__) + +#define _MAX_PATH MAX_PATH + +#define _access access +#define _strdup strdup + +#endif diff --git a/netinstall/postinstall.cc b/netinstall/postinstall.cc new file mode 100644 index 0000000..bf26f66 --- /dev/null +++ b/netinstall/postinstall.cc @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to run all the post-install scripts + in their various forms. */ + +#include "win32.h" + +#include +#include +#include +#ifndef WIN32_NATIVE +#include +#endif + +#include "state.h" +#include "dialog.h" +#include "find.h" +#include "concat.h" +#include "regedit.h" +#include "reginfo.h" +#include "resource.h" +#include "port.h" + +static char *sh = 0; +static char *cmd = 0; +static OSVERSIONINFO verinfo; + +static void +run (char *shscript, char *args, char *file) +{ + BOOL b; + char cmdline [_MAX_PATH]; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + sprintf (cmdline, "%s %s %s", shscript, args, file); + memset (&pi, 0, sizeof (pi)); + memset (&si, 0, sizeof (si)); + si.cb = sizeof (si); + si.lpTitle = "XEmacs Setup Post-Install Script"; + si.dwFlags = STARTF_USEPOSITION; + + b = CreateProcess (0, cmdline, 0, 0, 0, + CREATE_NEW_CONSOLE, 0, root_dir, &si, &pi); + + if (b) + WaitForSingleObject (pi.hProcess, INFINITE); +} + +static void +each (char *fname, unsigned int size) +{ + char *ext = strrchr (fname, '.'); + if (!ext) + return; + + if (sh && strcmp (ext, ".sh") == 0) + { + char *f2 = concat (root_dir, XEMACS_SETUP_DIR, "postinstall/", fname, 0); + run (sh, "-c", f2); + free (f2); + } + else if (cmd && strcmp (ext, ".bat") == 0) + { + char *f2 = backslash (concat (root_dir, XEMACS_SETUP_DIR, "postinstall/", + fname, 0)); + run (cmd, "/c", f2); + free (f2); + } + else + return; + + rename (concat (root_dir, XEMACS_SETUP_DIR, "postinstall/", fname, 0), + concat (root_dir, XEMACS_SETUP_DIR, "postinstall/", fname, ".done", 0)); +} + +static char *shells [] = { + "/bin/sh.exe", + "/usr/bin/sh.exe", + "/bin/bash.exe", + "/usr/bin/bash.exe", + 0 +}; + +void +do_postinstall (HINSTANCE h) +{ + int issystem; + next_dialog = 0; + char* cygroot = find_cygwin_root (&issystem); + int i; + for (i=0; shells[i]; i++) + { + sh = backslash (concat (cygroot, shells[i], 0)); + if (_access (sh, 0) == 0) + break; + free (sh); + sh = 0; + } + + char old_path[_MAX_PATH]; + GetEnvironmentVariable ("PATH", old_path, sizeof (old_path)); +#if 0 + SetEnvironmentVariable ("PATH", + backslash (concat (root_dir, "/bin;", + root_dir, "/usr/bin;", + old_path, 0))); + + SetEnvironmentVariable ("CYGWINROOT", root_dir); +#endif + SetCurrentDirectory (root_dir); + + verinfo.dwOSVersionInfoSize = sizeof (verinfo); + GetVersionEx (&verinfo); + + switch (verinfo.dwPlatformId) + { + case VER_PLATFORM_WIN32_NT: + cmd = "cmd.exe"; + break; + case VER_PLATFORM_WIN32_WINDOWS: + cmd = "command.com"; + break; + default: + cmd = "command.com"; + break; + } + + find (concat (root_dir, XEMACS_SETUP_DIR, "postinstall", 0), each); +} diff --git a/netinstall/regedit.cc b/netinstall/regedit.cc new file mode 100644 index 0000000..0c69495 --- /dev/null +++ b/netinstall/regedit.cc @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Manipulate the registry for XEmacs. */ + +#include "win32.h" + +#include +#if defined(CYGWIN) || defined(MINGW) +#include +#include +#endif + +#include "reginfo.h" +#include "regedit.h" +#include "msg.h" +#include "resource.h" +#include "dialog.h" + +static char * +find_cygwin_mount (HKEY rkey, int *istext) +{ + char buf[1000]; + char *retval = 0; + HKEY key; + DWORD retvallen = 0; + DWORD flags = 0; + DWORD type; + +#if defined(CYGWIN) || defined(MINGW) + sprintf (buf, "Software\\%s\\%s\\%s\\/", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME); + + if (RegOpenKeyEx (rkey, buf, 0, KEY_READ, &key) != ERROR_SUCCESS) + return 0; + + if (RegQueryValueEx (key, "native", 0, &type, 0, &retvallen) + == ERROR_SUCCESS) + { + retval = new char[retvallen+1]; + if (RegQueryValueEx (key, "native", 0, &type, (BYTE *)retval, &retvallen) + != ERROR_SUCCESS) + { + delete retval; + retval = 0; + } + } + + retvallen = sizeof (flags); + RegQueryValueEx (key, "flags", 0, &type, (BYTE *)&flags, &retvallen); + + RegCloseKey (key); + + if (retval) + *istext = (flags & MOUNT_BINARY) ? 0 : 1; + return retval; +#else + return 0; +#endif +} + +static char * +find_xemacs_root (HKEY rkey, int* isnative) +{ + char buf[1000]; + char *retval = 0; + HKEY key; + DWORD retvallen = 0; + DWORD type; + DWORD itype; + + sprintf (buf, "Software\\%s\\%s", + XEMACS_INFO_XEMACS_ORG_REGISTRY_NAME, + XEMACS_INFO_XEMACS_REGISTRY_NAME); + + if (RegOpenKeyEx (rkey, buf, 0, KEY_READ, &key) != ERROR_SUCCESS) + return 0; + + if (RegQueryValueEx (key, XEMACS_INFO_XEMACS_ROOT_KEY, + 0, &type, 0, &retvallen) == ERROR_SUCCESS) + { + retval = new char[retvallen+1]; + if (RegQueryValueEx (key, XEMACS_INFO_XEMACS_ROOT_KEY, + 0, &type, (BYTE *)retval, &retvallen) + != ERROR_SUCCESS) + { + delete retval; + retval = 0; + } + } + + retvallen = sizeof (itype); + RegQueryValueEx (key, XEMACS_INFO_XEMACS_ROOT_TYPE, + 0, &type, (BYTE *)&itype, &retvallen); + + if (itype == 1) + *isnative = 1; + else + *isnative = 0; + + RegCloseKey (key); + + return retval; +} + +char * +find_root_location (int *issystem, int *isnative) +{ + char *rv; + if ((rv = find_xemacs_root (HKEY_CURRENT_USER, isnative))) + { + *issystem = 0; + return rv; + } + else if ((rv = find_xemacs_root (HKEY_LOCAL_MACHINE, isnative))) + { + *issystem = 1; + return rv; + } + return 0; +} + +char * +find_cygwin_root (int *issystem) +{ + char *rv; + int istext; + if ((rv = find_cygwin_mount (HKEY_CURRENT_USER, &istext))) + { + *issystem = 0; + return rv; + } + else if ((rv = find_cygwin_mount (HKEY_LOCAL_MACHINE, &istext))) + { + *issystem = 1; + return rv; + } + return 0; +} + +void +create_xemacs_root (char *path, int issystem, int isnative) +{ + char buf[1000]; + HKEY key; + DWORD disposition; + DWORD itype = isnative ? 1 : 0; + + remove_xemacs_root (); + + sprintf (buf, "Software\\%s\\%s", + XEMACS_INFO_XEMACS_ORG_REGISTRY_NAME, + XEMACS_INFO_XEMACS_REGISTRY_NAME); + + HKEY kr = issystem ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + if (RegCreateKeyEx (kr, buf, 0, "XEmacs", 0, KEY_ALL_ACCESS, + 0, &key, &disposition) != ERROR_SUCCESS) + fatal ("create_xemacs_root"); + + RegSetValueEx (key, XEMACS_INFO_XEMACS_ROOT_KEY, + 0, REG_SZ, (BYTE *)path, strlen (path)+1); + RegSetValueEx (key, XEMACS_INFO_XEMACS_ROOT_TYPE, + 0, REG_DWORD, (BYTE *)&itype, sizeof (itype)); +} + +void +set_app_path (char *exe, char* path, int issystem) +{ + char buf[1000]; + HKEY key; + DWORD disposition; + + sprintf (buf, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s", + exe); + + HKEY kr = issystem ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + RegDeleteKey (kr, buf); + + if (RegCreateKeyEx (kr, buf, 0, "XEmacs", 0, KEY_ALL_ACCESS, + 0, &key, &disposition) != ERROR_SUCCESS) + fatal ("set_app_path"); + + RegSetValueEx (key, "Path", + 0, REG_SZ, (BYTE *)path, strlen (path)+1); +} + +static void +remove1 (HKEY rkey) +{ + char buf[1000]; + + sprintf (buf, "Software\\%s\\%s", + XEMACS_INFO_XEMACS_ORG_REGISTRY_NAME, + XEMACS_INFO_XEMACS_REGISTRY_NAME); + + RegDeleteKey (rkey, buf); +} + +void +remove_xemacs_root () +{ + remove1 (HKEY_LOCAL_MACHINE); + remove1 (HKEY_CURRENT_USER); +} + diff --git a/netinstall/regedit.h b/netinstall/regedit.h new file mode 100644 index 0000000..4944c9e --- /dev/null +++ b/netinstall/regedit.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Finds the existing root point, or returns NULL. */ + +char * find_root_location (int *issystem, int *isnative); +char * find_cygwin_root (int *issystem); + +/* Similar to the mount and umount functions, but simplified */ + +void create_xemacs_root (char *posix, int issystem, int isnative); +void remove_xemacs_root (); +void set_app_path (char *exe, char* path, int issystem); + diff --git a/netinstall/reginfo.h b/netinstall/reginfo.h new file mode 100644 index 0000000..36c0cd2 --- /dev/null +++ b/netinstall/reginfo.h @@ -0,0 +1,56 @@ +/* reginfo.h -- XEmacs version numbers and accompanying documentation. + +Copyright (C) 2000 Andy Piper. */ + +#define XEMACS_INFO_XEMACS_ORG_REGISTRY_NAME "GNU" +#define XEMACS_INFO_XEMACS_REGISTRY_NAME "XEmacs" +/* Keys */ +#define XEMACS_INFO_XEMACS_ROOT_KEY "emacs_dir" +#define XEMACS_INFO_XEMACS_ROOT_TYPE "install_type" +#define XEMACS_INFO_XEMACS_PACKAGE_KEY "EMACSPACKAGEPATH" +#define XEMACS_INFO_XEMACS_VERSION_KEY "version" + +#define XEMACS_DEFAULT_ROOT "\\Program Files\\XEmacs" +#define XEMACS_CYGWIN_DEFAULT_ROOT "\\usr\\local" + +#define XEMACS_SETUP_DIR \ + ((char*)(install_type == IDC_INSTALL_NATIVE ? "\\setup\\" : "/lib/xemacs/setup/")) +#define XEMACS_RESOURCE_DIR \ + ((char*)(install_type == IDC_INSTALL_NATIVE ? "\\" : "/lib/xemacs/")) +#define XEMACS_PACKAGE_DIR \ + ((char*)(install_type == IDC_INSTALL_NATIVE ? "\\xemacs-packages\\" \ + : "/lib/xemacs/xemacs-packages/")) +#define XEMACS_NATIVE_ARCH_NAME "i586-pc-win32" +#define XEMACS_CYGWIN_ARCH_NAME "i686-pc-cygwin32" + +/* + * Installation hierarchy is: + * C:\Program Files\XEmacs + * \xemacs-packages + * \etc + * \info + * \lib-src + * \lisp + * \man + * \pkginfo + * \site-packages + * \mule-packages + * \XEmacs-21.2 + * \i586-pc-win32 + * \etc + * \info + * \lisp + * Or: + * /usr/local/lib + * /xemacs/xemacs-packages + * /xemacs/site-packages + * /xemacs/mule-packages + * /xemacs-21.2 + * /i686-pc-cygwin32 + * /etc + * /info + * /lisp + * /usr/local/bin/i686-pc-cygwin32 + */ + + diff --git a/netinstall/res.rc b/netinstall/res.rc new file mode 100644 index 0000000..2d59534 --- /dev/null +++ b/netinstall/res.rc @@ -0,0 +1,513 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SOURCE DIALOG DISCARDABLE 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15,WS_DISABLED + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + LTEXT "Setup will use the following installation method.", + IDC_STATIC,112,11,170,17 + LTEXT "To exit setup click Cancel at any time.",IDC_STATIC,112, + 32,166,17 + CONTROL "Download from the Internet",IDC_SOURCE_DOWNLOAD,"Button", + BS_AUTORADIOBUTTON,127,102,152,10 + CONTROL "Install from the Internet",IDC_SOURCE_NETINST,"Button", + BS_AUTORADIOBUTTON,127,121,87,10 + CONTROL "Install from Local Directory",IDC_SOURCE_CWD,"Button", + BS_AUTORADIOBUTTON,127,140,104,10 + GROUPBOX "Installation method",IDC_STATIC,113,84,188,77 + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_LOCAL_DIR DIALOG DISCARDABLE 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Local package directory" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15,WS_DISABLED + PUSHBUTTON "< Back",IDC_BACK,154,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + EDITTEXT IDC_LOCAL_DIR,120,138,122,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_LOCAL_DIR_BROWSE,252,137,38,14 + LTEXT "Setup will use the following folder to install XEmacs and / or packages from.", + IDC_STATIC,112,10,170,17 + LTEXT "To select a different folder, click Browse and select another folder.", + IDC_STATIC,112,36,170,18 + LTEXT "To exit setup click Cancel at any time.",IDC_STATIC,112, + 63,166,17 + GROUPBOX "Local Package Directory",IDC_STATIC,112,126,186,31 + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_ROOT DIALOG DISCARDABLE 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15 + PUSHBUTTON "< Back",IDC_BACK,154,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + EDITTEXT IDC_ROOT_DIR,120,138,122,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_ROOT_BROWSE,252,137,38,14 + LTEXT "Setup will use the following folder in which to install XEmacs and / or packages.", + IDC_STATIC,112,10,170,17 + LTEXT "To select a different folder, click Browse and select another folder.", + IDC_STATIC,112,35,170,18 + LTEXT "To exit setup click Cancel at any time.",IDC_STATIC,112, + 63,166,17 + GROUPBOX "Installation Root Directory",IDC_STATIC,112,126,186,31 + CONTROL "All",IDC_ROOT_SYSTEM,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,177,110,25,8 + CONTROL "Just Me",IDC_ROOT_USER,"Button",BS_AUTORADIOBUTTON,220, + 110,50,8 + LTEXT "Installation Type :",IDC_STATIC,112,95,60,8 + LTEXT "Install For :",IDC_STATIC,112,110,43,8 + CONTROL "Native",IDC_INSTALL_NATIVE,"Button",BS_AUTORADIOBUTTON, + 177,93,37,10 + CONTROL "Cygwin",IDC_INSTALL_CYGWIN,"Button",BS_AUTORADIOBUTTON, + 220,93,39,10 + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_SITE DIALOG DISCARDABLE 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15 + PUSHBUTTON "< Back",IDC_BACK,154,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + LTEXT "Select Download Site",IDC_STATIC,113,11,135,11 + LISTBOX IDC_URL_LIST,121,24,179,136,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_OTHER_URL DIALOG DISCARDABLE 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15 + PUSHBUTTON "< Back",IDC_BACK,154,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + EDITTEXT IDC_OTHER_URL,120,138,170,12,ES_AUTOHSCROLL + LTEXT "Setup will use the following URL to install XEmacs and / or packages from.", + IDC_STATIC,112,10,170,17 + LTEXT "To select a different URL, edit the text.",IDC_STATIC, + 112,36,170,18 + LTEXT "To exit setup click Cancel at any time.",IDC_STATIC,112, + 58,166,17 + GROUPBOX "Select URL to download from",IDC_STATIC,112,126,186,31 + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_NET DIALOGEX 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15 + PUSHBUTTON "< Back",IDC_BACK,154,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + LTEXT "Setup will use the following connection method.", + IDC_STATIC,112,11,170,17 + LTEXT "To exit setup click Cancel at any time.",IDC_STATIC,112, + 32,166,17 + CONTROL "Use IE5 Settings",IDC_NET_IE5,"Button", + BS_AUTORADIOBUTTON,128,93,69,10 + CONTROL "Direct Connection",IDC_NET_DIRECT,"Button", + BS_AUTORADIOBUTTON,128,109,73,10 + CONTROL "Use HTTP/FTP Proxy:",IDC_NET_PROXY,"Button", + BS_AUTORADIOBUTTON,128,124,88,10 + EDITTEXT IDC_PROXY_HOST,128,141,80,12,ES_AUTOHSCROLL | + WS_DISABLED + LTEXT "Proxy",IDC_STATIC,10,55,50,15,SS_CENTERIMAGE, + WS_EX_RIGHT + LTEXT "Port",IDC_STATIC,229,139,20,15,SS_CENTERIMAGE, + WS_EX_RIGHT + EDITTEXT IDC_PROXY_PORT,257,141,30,12,ES_AUTOHSCROLL | + WS_DISABLED + GROUPBOX "Installation method",IDC_STATIC,113,78,188,83 + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_DLSTATUS DIALOG DISCARDABLE 0, 0, 215, 95 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,165,75,45,15 + LTEXT "Downloading...",IDC_STATIC,55,15,135,8 + LTEXT "(URL)",IDC_DLS_URL,55,30,150,8 + LTEXT "(RATE)",IDC_DLS_RATE,55,45,155,8 + CONTROL "Progress1",IDC_DLS_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,55,60,155,10 + ICON IDI_XEMACS,IDC_STATIC,5,5,20,20 +END + +IDD_INSTATUS DIALOG DISCARDABLE 0, 0, 215, 95 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,165,75,45,15 + LTEXT "Installing...",IDC_INS_ACTION,55,5,135,8 + LTEXT "(PKG)",IDC_INS_PKG,55,15,150,8 + LTEXT "(FILE)",IDC_INS_FILE,55,25,155,8 + CONTROL "Progress1",IDC_INS_DISKFULL,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,55,60,155,10 + ICON IDI_XEMACS,IDC_STATIC,5,5,20,20 + CONTROL "Progress1",IDC_INS_IPROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,55,50,155,10 + CONTROL "Progress1",IDC_INS_PPROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,55,40,155,10 + RTEXT "Package",IDC_STATIC,5,40,45,8 + RTEXT "Total",IDC_STATIC,10,50,40,8 + RTEXT "Disk",IDC_STATIC,5,60,45,8 +END + +IDD_PROXY_AUTH DIALOG DISCARDABLE 0, 0, 215, 95 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDI_XEMACS,IDC_STATIC,5,5,20,20 + EDITTEXT IDC_NET_USER,65,28,145,12,ES_AUTOHSCROLL + LTEXT "Proxy User ID",IDC_STATIC,5,28,55,15,SS_CENTERIMAGE, + WS_EX_RIGHT + EDITTEXT IDC_NET_PASSWD,65,43,145,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Password",IDC_STATIC,10,43,50,15,SS_CENTERIMAGE, + WS_EX_RIGHT + LTEXT "Proxy Authorization Required",IDC_STATIC,65,10,145,10 + DEFPUSHBUTTON "OK",IDOK,100,75,45,15,WS_DISABLED + PUSHBUTTON "Cancel",IDCANCEL,165,75,45,15 +END + +IDD_NET_AUTH DIALOG DISCARDABLE 0, 0, 215, 95 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDI_XEMACS,IDC_STATIC,5,5,20,20 + EDITTEXT IDC_NET_USER,65,28,145,12,ES_AUTOHSCROLL + LTEXT "User ID",IDC_STATIC,5,28,55,15,SS_CENTERIMAGE, + WS_EX_RIGHT + EDITTEXT IDC_NET_PASSWD,65,43,145,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Password",IDC_STATIC,10,43,50,15,SS_CENTERIMAGE, + WS_EX_RIGHT + LTEXT "Server Authorization Required",IDC_STATIC,65,10,145,10 + DEFPUSHBUTTON "OK",IDOK,100,75,45,15,WS_DISABLED + PUSHBUTTON "Cancel",IDCANCEL,165,75,45,15 +END + +IDD_SPLASH DIALOGEX 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + ICON IDI_XEMACS,IDC_STATIC,107,10,20,20 + LTEXT "Welcome to the XEmacs Net Release Setup Program. This will install XEmacs and/or associated packages on your computer.", + IDC_STATIC,133,10,158,29 + LTEXT "Version (unknown)",IDC_VERSION,112,117,120,10 + LTEXT "Copyright (C) 2000 Red Hat Inc",IDC_STATIC,111,132,135, + 8 + LTEXT "http://www.xemacs.org/",IDC_STATIC,111,147,150,10 + LTEXT "It is strongly recommended that you exit all Windows programs before running this utility.", + IDC_STATIC,110,43,191,19 + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + +IDD_CHOOSE DIALOG DISCARDABLE 0, 0, 311, 239 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Next >",IDOK,199,214,45,15 + PUSHBUTTON "< Back",IDC_BACK,154,214,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,214,45,15 + LTEXT "",IDC_STATIC,10,201,291,1,SS_SUNKEN | NOT WS_GROUP + LTEXT "Select packages to install",IDC_STATIC,55,5,85,8 + ICON IDI_XEMACS,IDC_STATIC,5,5,21,20 + LTEXT "",IDC_LISTVIEW_POS,55,15,230,155,SS_SUNKEN | NOT + WS_VISIBLE | NOT WS_GROUP + CONTROL "SPIN",IDC_STATIC,"Static",SS_BITMAP,55,170,15,13 + LTEXT "= click to choose action, (p) = previous version, (x) = experimental", + IDC_STATIC,65,170,220,8 + PUSHBUTTON "Full/Part",IDC_CHOOSE_FULLPART,250,5,35,10 + PUSHBUTTON "Exp",IDC_CHOOSE_EXP,215,5,25,10 + PUSHBUTTON "Curr",IDC_CHOOSE_CURR,190,5,25,10 + PUSHBUTTON "Prev",IDC_CHOOSE_PREV,165,5,25,10 +END + +IDD_DESKTOP DIALOG DISCARDABLE 0, 0, 311, 201 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "XEmacs Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Finish",IDOK,199,176,45,15 + PUSHBUTTON "< Back",IDC_BACK,154,176,45,15 + PUSHBUTTON "Cancel",IDCANCEL,256,176,45,15 + LTEXT "",IDC_STATIC,10,10,87,151,SS_SUNKEN | NOT WS_GROUP + LTEXT "",IDC_STATIC,10,169,291,1,SS_SUNKEN | NOT WS_GROUP + LTEXT "Setup has now finished. To create desktop shortcuts, please select from the following options.", + IDC_STATIC,112,11,170,17 + LTEXT "To complete setup click Finish.",IDC_STATIC,112,32,166, + 17 + CONTROL "Create Desktop Icon",IDC_ROOT_DESKTOP,"Button", + BS_AUTOCHECKBOX,113,76,100,8 + CONTROL "Add to Start Menu",IDC_ROOT_MENU,"Button", + BS_AUTOCHECKBOX,113,97,100,8 + CONTROL "GNU",IDC_STATIC,"Static",SS_BITMAP,19,36,69,62 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_XEMACS ICON DISCARDABLE "xemacs.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// FILE +// + +XEMACS.ICON FILE DISCARDABLE "xemacs.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_SOURCE, DIALOG + BEGIN + VERTGUIDE, 113 + VERTGUIDE, 127 + END + + IDD_LOCAL_DIR, DIALOG + BEGIN + VERTGUIDE, 112 + HORZGUIDE, 10 + END + + IDD_ROOT, DIALOG + BEGIN + VERTGUIDE, 112 + HORZGUIDE, 103 + HORZGUIDE, 118 + END + + IDD_SITE, DIALOG + BEGIN + HORZGUIDE, 11 + HORZGUIDE, 161 + END + + IDD_NET, DIALOG + BEGIN + VERTGUIDE, 128 + BOTTOMMARGIN, 191 + HORZGUIDE, 153 + END + + IDD_PROXY_AUTH, DIALOG + BEGIN + BOTTOMMARGIN, 49 + END + + IDD_NET_AUTH, DIALOG + BEGIN + BOTTOMMARGIN, 49 + END + + IDD_SPLASH, DIALOG + BEGIN + LEFTMARGIN, 10 + RIGHTMARGIN, 301 + TOPMARGIN, 10 + BOTTOMMARGIN, 191 + END + + IDD_CHOOSE, DIALOG + BEGIN + BOTTOMMARGIN, 229 + HORZGUIDE, 214 + END + + IDD_DESKTOP, DIALOG + BEGIN + VERTGUIDE, 113 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +SPIN BITMAP DISCARDABLE "choose-spin.bmp" +IDB_SPIN BITMAP DISCARDABLE "choose-spin.bmp" +IDB_RTARROW BITMAP DISCARDABLE "choose-rtarrow.bmp" +IDB_CHECK_YES BITMAP DISCARDABLE "check-yes.bmp" +IDB_CHECK_NO BITMAP DISCARDABLE "check-no.bmp" +IDB_CHECK_NA BITMAP DISCARDABLE "check-na.bmp" +GNU BITMAP DISCARDABLE "gnu.bmp" +IDB_GNU BITMAP DISCARDABLE "gnu.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ROOT_SLASH "Warning: we recommend you do NOT use the root of your hard drive as the XEmacs root. Proceed anyway?" + IDS_ROOT_SPACE "You should not choose a root path that include spaces in directory names. Proceed anyway?" + IDS_MIRROR_LST "http://ftp.xemacs.org/pub/xemacs/mirrors.lst" + IDS_DIALOG_FAILED "Unable to create Dialog Box" + IDS_CYGWIN_FUNC_MISSING "Error: unable to find function `%s' in %s" + IDS_DOWNLOAD_SHORT "Download error: %s too short (%d, wanted %d)" + IDS_ERR_OPEN_WRITE "Can't open %s for writing: %s" + IDS_SETUPINI_MISSING "Unable to get setup.ini from %s" + IDS_OLD_SETUPINI "This setup.ini is older than the one you used last time you installed cygwin. Proceed anyway?" + IDS_ERR_RENAME "Can't rename %s to %s: %s" + IDS_NOTHING_INSTALLED "Nothing needed to be installed" + IDS_INSTALL_COMPLETE "Installation Complete" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ERR_OPEN_READ "Can't open %s for reading: %s" + IDS_ROOT_ABSOLUTE "The install directory must be absolute, with both a drive letter and leading slash, like C:\\Cygwin" + IDS_DOWNLOAD_COMPLETE "Download Complete" + IDS_CVSID "\n%%% $Id: res.rc,v 1.1.2.3 2000/12/27 09:35:11 andyp Exp $\n" + IDS_NOLOGFILE "Cannot open log file %s for writing" + IDS_UNINSTALL_COMPLETE "Uninstalls complete." + IDS_WININET "Unable to find or load the Internet Explorer 5 DLLs" + IDS_ERR_CHDIR "Could not change dir to %s" + IDS_OLD_SETUP_VERSION "This setup is version %s, but setup.ini claims version %s is available.\nYou might want to upgrade to get the latest features and bug fixes." + IDS_DOWNLOAD_FAILED "Unable to download %s" + IDS_DOWNLOAD_INCOMPLETE "Download Incomplete. Try again?" + IDS_INSTALL_INCOMPLETE "Installation incomplete. Check /setup.log.full for details" + IDS_ROOT_NOCYGWIN "You should not install the Cygwin version without Cygwin installed. Proceed anyway?" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/netinstall/resource.h b/netinstall/resource.h new file mode 100644 index 0000000..20cf78b --- /dev/null +++ b/netinstall/resource.h @@ -0,0 +1,113 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by res.rc +// +#define IDS_ROOT_SLASH 1 +#define IDS_ROOT_SPACE 2 +#define IDS_CWD_NONEMPTY 3 +#define IDS_MIRROR_LST 6 +#define IDS_DIALOG_FAILED 7 +#define IDS_CYGWIN_FUNC_MISSING 8 +#define IDS_DOWNLOAD_SHORT 9 +#define IDS_ERR_OPEN_WRITE 10 +#define IDS_SETUPINI_MISSING 11 +#define IDS_OLD_SETUPINI 12 +#define IDS_ERR_RENAME 13 +#define IDS_NOTHING_INSTALLED 14 +#define IDS_INSTALL_COMPLETE 15 +#define IDS_ERR_OPEN_READ 16 +#define IDS_ROOT_ABSOLUTE 17 +#define IDS_DOWNLOAD_COMPLETE 18 +#define IDS_CVSID 19 +#define IDS_NOLOGFILE 20 +#define IDS_UNINSTALL_COMPLETE 21 +#define IDS_WININET 22 +#define IDS_ERR_CHDIR 23 +#define IDS_OLD_SETUP_VERSION 24 +#define IDS_DOWNLOAD_FAILED 25 +#define IDS_DOWNLOAD_INCOMPLETE 26 +#define IDS_INSTALL_INCOMPLETE 27 +#define IDS_ROOT_NOCYGWIN 28 +#define IDD_ROOT 101 +#define IDD_SOURCE 102 +#define IDD_OTHER_URL 103 +#define IDD_SITE 104 +#define IDD_NET 105 +#define IDD_DLSTATUS 106 +#define IDD_S_LOAD_INI 107 +#define IDD_S_FROM_CWD 108 +#define IDD_CHOOSE 109 +#define IDD_S_DOWNLOAD 110 +#define IDD_S_INSTALL 111 +#define IDD_INSTATUS 112 +#define IDD_DESKTOP 113 +#define IDD_PROXY_AUTH 114 +#define IDD_S_POSTINSTALL 115 +#define IDD_NET_AUTH 116 +#define IDD_SPLASH 117 +#define IDB_SPIN 118 +#define IDB_RTARROW 119 +#define IDI_SPIN 120 +#define IDI_XEMACS 121 +#define IDD_LOCAL_DIR 122 +#define IDB_CHECK_YES 123 +#define IDB_CHECK_NO 124 +#define IDB_CHECK_NA 125 +#define IDB_GNU 126 +#define IDC_SOURCE_DOWNLOAD 1000 +#define IDC_SOURCE_NETINST 1001 +#define IDC_SOURCE_CWD 1002 +#define IDC_ROOT_DIR 1003 +#define IDC_ROOT_BROWSE 1004 +#define IDC_ROOT_TEXT 1005 +#define IDC_ROOT_BINARY 1006 +#define IDC_URL_LIST 1007 +#define IDC_SITE_NEXT 1008 +#define IDC_BACK 1009 +#define IDC_OTHER_URL 1010 +#define IDC_NET_IE5 1011 +#define IDC_NET_DIRECT 1012 +#define IDC_NET_PROXY 1013 +#define IDC_PROXY_HOST 1014 +#define IDC_PROXY_PORT 1015 +#define IDC_PROXY_USER 1016 +#define IDC_DLS_PROGRESS 1019 +#define IDC_DLS_URL 1020 +#define IDC_DLS_RATE 1021 +#define IDC_INS_PKG 1022 +#define IDC_INS_FILE 1023 +#define IDC_INS_DISKFULL 1024 +#define IDC_INS_IPROGRESS 1025 +#define IDC_INS_PPROGRESS 1026 +#define IDC_ROOT_SYSTEM 1028 +#define IDC_ROOT_USER 1029 +#define IDC_NET_USER 1030 +#define IDC_NET_PASSWD 1031 +#define IDC_VERSION 1033 +#define IDC_LISTVIEW_POS 1034 +#define IDC_CHOOSE_FULLPART 1035 +#define IDC_CHOOSE_EXP 1036 +#define IDC_CHOOSE_CURR 1037 +#define IDC_CHOOSE_PREV 1038 +#define IDC_CHOOSE_LIST 1039 +#define IDC_INS_ACTION 1040 +#define IDC_ROOT_DESKTOP 1041 +#define IDC_ROOT_MENU 1042 +#define IDC_LOCAL_DIR_BROWSE 1043 +#define IDC_LOCAL_DIR 1044 +#define IDC_INSTALL_NATIVE 1045 +#define IDC_INSTALL_CYGWIN 1046 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 127 +#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_CONTROL_VALUE 1050 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/netinstall/root.cc b/netinstall/root.cc new file mode 100644 index 0000000..2378151 --- /dev/null +++ b/netinstall/root.cc @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to ask the user where they want the + root of the installation to be, and to ask whether the user prefers + text or binary mounts. */ + +#include "win32.h" +#include +#include +#include +#include + +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "msg.h" +#include "regedit.h" +#include "reginfo.h" +#include "concat.h" +#include "log.h" + +static int rb[] = { IDC_INSTALL_CYGWIN, IDC_INSTALL_NATIVE, 0 }; +static int su[] = { IDC_ROOT_SYSTEM, IDC_ROOT_USER, 0 }; + +static void +check_if_enable_next (HWND h) +{ + EnableWindow (GetDlgItem (h, IDOK), install_type && root_dir && root_scope); +} + +static void +load_dialog (HWND h) +{ + rbset (h, rb, install_type); + rbset (h, su, root_scope); + eset (h, IDC_ROOT_DIR, root_dir); + check_if_enable_next (h); +} + +static void +save_dialog (HWND h) +{ + install_type = rbget (h, rb); + root_scope = rbget (h, su); + char* new_root_dir = eget (h, IDC_ROOT_DIR, root_dir); + + if (!root_dir || strcmp (new_root_dir, root_dir) != 0) + root_dir_default = 0; + + root_dir = new_root_dir; +} + +/* + * is_admin () determines whether or not the current user is a member of the + * Administrators group. On Windows 9X, the current user is considered an + * Administrator by definition. + */ + +static int +is_admin () +{ + // Windows 9X users are considered Administrators by definition + OSVERSIONINFO verinfo; + verinfo.dwOSVersionInfoSize = sizeof (verinfo); + GetVersionEx (&verinfo); + if (verinfo.dwPlatformId != VER_PLATFORM_WIN32_NT) + return 1; + + // Get the process token for the current process + HANDLE token; + BOOL status = OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &token); + if (!status) + return 0; + + // Get the group token information + UCHAR token_info[1024]; + PTOKEN_GROUPS groups = (PTOKEN_GROUPS) token_info; + DWORD token_info_len = sizeof (token_info); + status = GetTokenInformation (token, TokenGroups, token_info, token_info_len, &token_info_len); + CloseHandle(token); + if (!status) + return 0; + + // Create the Administrators group SID + PSID admin_sid; + SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY; + status = AllocateAndInitializeSid (&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &admin_sid); + if (!status) + return 0; + + // Check to see if the user is a member of the Administrators group + status = 0; + for (UINT i=0; iGroupCount; i++) { + if (EqualSid(groups->Groups[i].Sid, admin_sid)) { + status = 1; + break; + } + } + + // Destroy the Administrators group SID + FreeSid (admin_sid); + + // Return whether or not the user is a member of the Administrators group + return status; +} + +static void +change_default_root (int id) +{ + int issystem; + char* cygroot = find_cygwin_root (&issystem); + if (id == IDC_INSTALL_CYGWIN && cygroot) + { + root_dir = concat (cygroot, XEMACS_CYGWIN_DEFAULT_ROOT, 0); + install_type = IDC_INSTALL_CYGWIN; + } + else if (id == IDC_INSTALL_NATIVE) + { + char windir[_MAX_PATH]; + GetWindowsDirectory (windir, sizeof (windir)); + windir[2] = 0; + root_dir = concat (windir, XEMACS_DEFAULT_ROOT, 0); + install_type = IDC_INSTALL_NATIVE; + } +} + +static void +read_mount_table () +{ + int isnative, issystem; + root_dir = find_root_location (&issystem, &isnative); + if (root_dir) + { + if (isnative) + install_type = IDC_INSTALL_NATIVE; + else + install_type = IDC_INSTALL_CYGWIN; + + if (issystem) + root_scope = IDC_ROOT_SYSTEM; + else + root_scope = IDC_ROOT_USER; + root_dir_default = 0; + } + else + { + change_default_root (IDC_INSTALL_NATIVE); + root_scope = (is_admin()) ? IDC_ROOT_SYSTEM : IDC_ROOT_USER; + root_dir_default = 1; + } +} + +static int CALLBACK +browse_cb (HWND h, UINT m, LPARAM lp, LPARAM data) +{ + switch (m) + { + case BFFM_INITIALIZED: + if (root_dir) + SendMessage (h, BFFM_SETSELECTION, TRUE, (LPARAM)root_dir); + break; + } + return 0; +} + +static void +browse (HWND h) +{ + BROWSEINFO bi; + CHAR name[MAX_PATH]; + LPITEMIDLIST pidl; + memset (&bi, 0, sizeof (bi)); + bi.hwndOwner = h; + bi.pszDisplayName = name; + bi.lpszTitle = "Select an installation root directory"; + bi.ulFlags = BIF_RETURNONLYFSDIRS; + bi.lpfn = browse_cb; + pidl = SHBrowseForFolder (&bi); + if (pidl) + { + if (SHGetPathFromIDList (pidl, name)) + eset (h, IDC_ROOT_DIR, name); + } +} + +#define isslash(c) ((c) == '\\' || (c) == '/') + +static int +directory_is_absolute () +{ + if (isalpha (root_dir[0]) + && root_dir[1] == ':' + && (root_dir[2] == '\\' || root_dir[2] == '/')) + return 1; + return 0; +} + +static int +directory_is_rootdir () +{ + char *c; + for (c = root_dir; *c; c++) + if (isslash (c[0]) && c[1] && !isslash (c[1])) + return 0; + return 1; +} + +static int +cygwin_without_cygwin () +{ + int issystem; + if (install_type == IDC_INSTALL_CYGWIN + && !find_cygwin_root (&issystem)) + return 1; + return 0; +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_ROOT_DIR: + case IDC_ROOT_SYSTEM: + case IDC_ROOT_USER: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDC_INSTALL_NATIVE: + case IDC_INSTALL_CYGWIN: + if (root_dir_default) + { + change_default_root (id); + eset (h, IDC_ROOT_DIR, root_dir); + } + save_dialog (h); + check_if_enable_next (h); + break; + + case IDC_ROOT_BROWSE: + browse (h); + break; + + case IDOK: + save_dialog (h); + + if (! directory_is_absolute ()) + { + note (IDS_ROOT_ABSOLUTE); + break; + } + + if (directory_is_rootdir ()) + if (IDNO == yesno (IDS_ROOT_SLASH)) + break; + + if (cygwin_without_cygwin ()) + if (IDNO == yesno (IDS_ROOT_NOCYGWIN)) + break; + + create_xemacs_root (root_dir, + root_scope == IDC_ROOT_SYSTEM ? 1 : 0, + install_type == IDC_INSTALL_NATIVE ? 1 : 0); + + switch (source) + { + case IDC_SOURCE_NETINST: + NEXT (IDD_NET); + break; + case IDC_SOURCE_CWD: + NEXT (IDD_S_FROM_CWD); + break; + default: + msg ("source is default? %d\n", source); + NEXT (0); + } + break; + + case IDC_BACK: + save_dialog (h); + NEXT (IDD_LOCAL_DIR); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +void +do_root (HINSTANCE h) +{ + int rv = 0; + read_mount_table (); + + rv = DialogBox (h, MAKEINTRESOURCE (IDD_ROOT), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); + + log (0, "root: %s %s %s", root_dir, + (install_type == IDC_INSTALL_NATIVE) ? "native" : "cygwin", + (root_scope == IDC_ROOT_USER) ? "user" : "system"); +} + diff --git a/netinstall/setup.mak b/netinstall/setup.mak new file mode 100644 index 0000000..333e00a --- /dev/null +++ b/netinstall/setup.mak @@ -0,0 +1,247 @@ +# Makefile for Microsoft NMAKE +# Copyright (C) 1995 Board of Trustees, University of Illinois. +# Copyright (C) 1995, 1996, 2000 Ben Wing. +# Copyright (C) 1995 Sun Microsystems, Inc. +# Copyright (C) 1998 Free Software Foundation, Inc. +# +# This file is part of XEmacs. +# +# XEmacs 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, or (at your option) any +# later version. +# +# XEmacs 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 XEmacs; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Synched up with: Not in FSF. +# + +TARGETOS=BOTH +APPVER=4.0 +!include "c:\Program Files\Microsoft Platform SDK\Include\win32.mak" + +default: all + +# APA: Since there seems to be no way to determine the directory where +# xemacs.mak is located (from within nmake) we just insist on the user +# to invoke nmake in the directory where xemacs.mak is. +!if !exist("$(MAKEDIR)\setup.mak") +!error Please run nmake from the directory of this makefile (xemacs\netinstall). +!endif + +XEMACS=$(MAKEDIR)\.. + +# Define a variable for the 'del' command to use +DEL=-del + +# Configuration from nt subdirectory if needed + +!include "$(XEMACS)\nt\config.inc" + +OUTDIR = obj + +# +# Compiler command echo control. Define VERBOSECC=1 to get verbose compilation. +# +!if !defined(VERBOSECC) +VERBOSECC=0 +!endif +!if $(VERBOSECC) +cc=$(cc) +!else +cc=@$(cc) +!endif + +!if $(DEBUG_XEMACS) +cdebug=-Od -Gr -Zi -Zp8 +!else +cdebug=-Oxsb2 -Oy- -G5rFs -Zi -Zp8 +!endif + +defines = -DWIN32_NATIVE -I$(ZLIBDIR) $(ZLIB_FLAGS) + +# +# Object files +# +OBJS = \ + $(OUTDIR)\choose.obj \ + $(OUTDIR)\concat.obj \ + $(OUTDIR)\desktop.obj \ + $(OUTDIR)\dialog.obj \ + $(OUTDIR)\diskfull.obj \ + $(OUTDIR)\download.obj \ + $(OUTDIR)\find.obj \ + $(OUTDIR)\fromcwd.obj \ + $(OUTDIR)\geturl.obj \ + $(OUTDIR)\hash.obj \ + $(OUTDIR)\ini.obj \ + $(OUTDIR)\inilex.obj \ + $(OUTDIR)\iniparse.obj \ + $(OUTDIR)\install.obj \ + $(OUTDIR)\localdir.obj \ + $(OUTDIR)\log.obj \ + $(OUTDIR)\main.obj \ + $(OUTDIR)\mkdir.obj \ + $(OUTDIR)\mklink2.obj \ + $(OUTDIR)\regedit.obj \ + $(OUTDIR)\msg.obj \ + $(OUTDIR)\net.obj \ + $(OUTDIR)\netio.obj \ + $(OUTDIR)\nio-ie5.obj \ + $(OUTDIR)\nio-file.obj \ + $(OUTDIR)\nio-ftp.obj \ + $(OUTDIR)\nio-http.obj \ + $(OUTDIR)\other.obj \ + $(OUTDIR)\postinstall.obj \ +# $(OUTDIR)\res.obj \ + $(OUTDIR)\root.obj \ + $(OUTDIR)\simpsock.obj \ + $(OUTDIR)\site.obj \ + $(OUTDIR)\source.obj \ + $(OUTDIR)\splash.obj \ + $(OUTDIR)\state.obj \ + $(OUTDIR)\tar.obj \ + $(OUTDIR)\version.obj + +# +# Libraries +# +LIBS = libcmt.lib $(olelibsmt) \ + kernel32.lib shell32.lib \ + wsock32.lib netapi32.lib \ + wininet.lib $(zlib) + +# Rules + +.SUFFIXES: +.SUFFIXES: .c .cc .obj .texi .info + +# nmake rule +.cc{$(OUTDIR)}.obj: + $(cc) /TP $(cflags) $(cdebug) $(cvarsmt) $(defines) -Fo$@ $< +.c{$(OUTDIR)}.obj: + $(cc) $(cflags) $(cdebug) $(cvarsmt) $(defines) -Fo$@ $< + +# +# Main target +# +all: setup.exe + +# +# Link target. setargv.obj is provided in the compiler library directory. +# +setup.exe: $(OUTDIR) $(OBJS) res.res + $(link) /OUT:$@ $(ldebug) $(guilflags) $(OBJS) res.res $(LIBS) + +iniparse.c iniparse.h : iniparse.y + bison -d -o iniparse.c $(srcdir)/iniparse.y + +$(OUTDIR)\inilex.obj: iniparse.h + +inilex.c : inilex.l iniparse.h + flex -t $(srcdir)/inilex.l | sed "/^extern int isatty YY/d" > inilex.c + +version.c : $(srcdir)/ChangeLog version.pl + perl version.pl < ChangeLog > version.c + +res.res: res.rc + $(rc) $(rcvars) $(rcflags) /fo$@ $** + +$(OUTDIR): + -@mkdir $(OUTDIR) + +install:: all + +clean:: + $(DEL) $(OUTDIR)\*.obj *.pdb *.aps res.res lex.yy.c + +distclean:: clean + $(DEL) *~ setup.exe + +# DO NOT DELETE + +$(OUTDIR)/autoload.obj: autoload.c win32.h +$(OUTDIR)/inilex.obj: inilex.c win32.h ini.h iniparse.h \ + +$(OUTDIR)/iniparse.obj: iniparse.c ini.h iniparse.h port.h +$(OUTDIR)/inilex.obj: inilex.c win32.h ini.h iniparse.h +$(OUTDIR)/mklink2.obj: mklink2.c win32.h +$(OUTDIR)/choose.obj: choose.cc win32.h dialog.h resource.h \ + state.h ini.h concat.h msg.h log.h find.h reginfo.h +$(OUTDIR)/concat.obj: concat.cc win32.h +$(OUTDIR)/desktop.obj: desktop.cc win32.h \ + resource.h ini.h msg.h state.h \ + concat.h mkdir.h dialog.h version.h reginfo.h regedit.h port.h +$(OUTDIR)/dialog.obj: dialog.cc win32.h dialog.h msg.h log.h \ + win32.h +$(OUTDIR)/diskfull.obj: diskfull.cc diskfull.h +$(OUTDIR)/download.obj: download.cc win32.h resource.h msg.h \ + ini.h dialog.h concat.h geturl.h state.h mkdir.h log.h +$(OUTDIR)/find.obj: find.cc win32.h port.h +$(OUTDIR)/fromcwd.obj: fromcwd.cc win32.h \ + ini.h resource.h concat.h \ + state.h dialog.h msg.h find.h version.h port.h +$(OUTDIR)/geturl.obj: geturl.cc win32.h dialog.h geturl.h \ + resource.h netio.h msg.h log.h +$(OUTDIR)/hash.obj: hash.cc win32.h hash.h +$(OUTDIR)/ini.obj: ini.cc win32.h ini.h resource.h concat.h \ + state.h geturl.h dialog.h msg.h mkdir.h log.h reginfo.h version.h +$(OUTDIR)/install.obj: install.cc win32.h \ + $(ZLIBDIR)/zlib.h $(ZLIBDIR)/zconf.h \ + resource.h ini.h dialog.h concat.h geturl.h mkdir.h state.h tar.h \ + diskfull.h msg.h regedit.h reginfo.h log.h hash.h port.h +$(OUTDIR)/localdir.obj: localdir.cc win32.h dialog.h resource.h \ + state.h msg.h concat.h log.h +$(OUTDIR)/log.obj: log.cc win32.h resource.h msg.h log.h dialog.h \ + state.h concat.h mkdir.h +$(OUTDIR)/main.obj: main.cc win32.h resource.h dialog.h state.h \ + msg.h netio.h find.h log.h port.h +$(OUTDIR)/mkdir.obj: mkdir.cc win32.h mkdir.h +$(OUTDIR)/msg.obj: msg.cc win32.h dialog.h log.h +$(OUTDIR)/net.obj: net.cc win32.h dialog.h resource.h state.h \ + msg.h log.h +$(OUTDIR)/netio.obj: netio.cc win32.h resource.h state.h msg.h \ + netio.h nio-file.h nio-ie5.h nio-http.h nio-ftp.h dialog.h log.h port.h \ + win32.h +$(OUTDIR)/nio-file.obj: nio-file.cc netio.h nio-file.h resource.h \ + msg.h +$(OUTDIR)/nio-ftp.obj: nio-ftp.cc win32.h resource.h state.h \ + simpsock.h log.h netio.h nio-ftp.h +$(OUTDIR)/nio-http.obj: nio-http.cc win32.h resource.h state.h \ + simpsock.h msg.h netio.h nio-http.h +$(OUTDIR)/nio-ie5.obj: nio-ie5.cc win32.h resource.h state.h \ + dialog.h msg.h netio.h nio-ie5.h +$(OUTDIR)/other.obj: other.cc win32.h dialog.h resource.h state.h \ + msg.h log.h +$(OUTDIR)/postinstall.obj: postinstall.cc win32.h \ + state.h dialog.h find.h \ + concat.h regedit.h reginfo.h resource.h port.h +$(OUTDIR)/regedit.obj: regedit.cc win32.h reginfo.h regedit.h \ + msg.h resource.h dialog.h +$(OUTDIR)/root.obj: root.cc win32.h dialog.h resource.h state.h \ + msg.h regedit.h reginfo.h concat.h log.h +$(OUTDIR)/simpsock.obj: simpsock.cc win32.h simpsock.h msg.h \ + win32.h +$(OUTDIR)/site.obj: site.cc dialog.h resource.h state.h geturl.h \ + msg.h concat.h regedit.h reginfo.h log.h port.h +$(OUTDIR)/source.obj: source.cc win32.h dialog.h resource.h \ + state.h msg.h log.h +$(OUTDIR)/splash.obj: splash.cc win32.h dialog.h resource.h msg.h \ + version.h +$(OUTDIR)/state.obj: state.cc state.h +$(OUTDIR)/tar.obj: tar.cc win32.h \ + $(ZLIBDIR)/zlib.h $(ZLIBDIR)/zconf.h \ + tar.h mkdir.h log.h port.h + +# +# Local Variables: +# mode: makefile +# End: diff --git a/netinstall/simpsock.cc b/netinstall/simpsock.cc new file mode 100644 index 0000000..db1f806 --- /dev/null +++ b/netinstall/simpsock.cc @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Simplified socket access functions */ + +#include "win32.h" +#include +#include +#include +#include + +#include "simpsock.h" +#include "msg.h" + +#define SSBUFSZ 1024 + +SimpleSocket::SimpleSocket (char *hostname, int port) +{ + static int initted = 0; + if (!initted) + { + initted = 1; + WSADATA d; + WSAStartup (MAKEWORD (1,1), &d); + } + + s = INVALID_SOCKET; + buf = (char *) malloc (SSBUFSZ + 3); + putp = getp = 0; + + int i1, i2, i3, i4; + unsigned char ip[4]; + + if (sscanf (hostname, "%d.%d.%d.%d", &i1, &i2, &i3, &i4) == 4) + { + ip[0] = i1; + ip[1] = i2; + ip[2] = i3; + ip[3] = i4; + } + else + { + struct hostent *he; + he = gethostbyname (hostname); + if (!he) + { + msg ("Can't resolve `%s'\n", hostname); + return; + } + memcpy (ip, he->h_addr_list[0], 4); + } + + s = socket (AF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) + { + msg ("Can't create socket, %d", WSAGetLastError ()); + return; + } + + struct sockaddr_in name; + + memset (&name, 0, sizeof (name)); + name.sin_family = AF_INET; + name.sin_port = htons (port); + memcpy (&name.sin_addr, ip, 4); + + if (connect (s, (sockaddr *)&name, sizeof(name))) + { + msg ("Can't connect to %s:%d", hostname, port); + closesocket (s); + s = INVALID_SOCKET; + return; + } + + return; +} + +SimpleSocket::~SimpleSocket () +{ + if (s != INVALID_SOCKET) + closesocket (s); + s = INVALID_SOCKET; + if (buf) + free (buf); + buf = 0; +} + +int +SimpleSocket::ok () +{ + if (s == INVALID_SOCKET) + return 0; + return 1; +} + +int +SimpleSocket::printf (char *fmt, ...) +{ + char localbuf[SSBUFSZ]; + va_list args; + va_start (args, fmt); + vsprintf (localbuf, fmt, args); + return send (s, localbuf, strlen (localbuf), 0); +} + +int +SimpleSocket::write (char *localbuf, int len) +{ + return send (s, localbuf, len, 0); +} + +int +SimpleSocket::fill () +{ + if (putp == getp) + putp = getp = 0; + + int n = SSBUFSZ - putp; + if (n == 0) + return 0; + int r = recv (s, buf + putp, n, 0); + if (r > 0) + { + putp += r; + return r; + } + return 0; +} + +char * +SimpleSocket::gets () +{ + if (getp > 0 && putp > getp) + { + memmove (buf, buf+getp, putp-getp); + putp -= getp; + getp = 0; + } + if (putp == getp) + fill(); + + // getp is zero, always, here, and putp is the count + char *nl; + while ((nl = (char *)memchr (buf, '\n', putp)) == NULL && putp < SSBUFSZ) + if (fill () <= 0) + break; + + if (nl) + { + getp = nl - buf + 1; + while ((*nl == '\n' || *nl == '\r') && nl >= buf) + *nl-- = 0; + } + else + { + getp = putp; + nl = buf + putp; + nl[1] = 0; + } + + return buf; +} + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +int +SimpleSocket::read (char *ubuf, int ulen) +{ + int n, rv=0; + if (putp > getp) + { + n = MIN (ulen, putp-getp); + memmove (ubuf, buf+getp, n); + getp += n; + ubuf += n; + ulen -= n; + rv += n; + } + while (ulen > 0) + { + n = recv (s, ubuf, ulen, 0); + if (n <= 0) + return rv; + ubuf += n; + ulen -= n; + rv += n; + } + return rv; +} diff --git a/netinstall/simpsock.h b/netinstall/simpsock.h new file mode 100644 index 0000000..cde49dd --- /dev/null +++ b/netinstall/simpsock.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Simplified socket access functions */ + +class SimpleSocket { + + SOCKET s; + char *buf; + int putp, getp; + int fill (); + + public: + SimpleSocket (char *hostname, int port); + ~SimpleSocket (); + + int ok (); + + int printf (char *fmt, ...); + int write (char *buf, int len); + + char *gets (); + int read (char *buf, int len); +}; diff --git a/netinstall/site.cc b/netinstall/site.cc new file mode 100644 index 0000000..f7eacf1 --- /dev/null +++ b/netinstall/site.cc @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to get the list of mirror sites and ask + the user which mirror site they want to download from. */ + +#include "win32.h" +#include +#include +#include + +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "geturl.h" +#include "msg.h" +#include "concat.h" +#include "regedit.h" +#include "reginfo.h" +#include "log.h" + +#include "port.h" + +#define NO_IDX (-1) +#define OTHER_IDX (-2) + +typedef struct { + char *url; + char *displayed_url; + char *sort_key; +} site_list_type; + +static site_list_type *site_list = 0; +static int list_idx = NO_IDX; +static int mirror_idx = NO_IDX; + +static void +check_if_enable_next (HWND h) +{ + EnableWindow (GetDlgItem (h, IDOK), (mirror_idx != NO_IDX) ? 1 : 0); +} + +static void +load_dialog (HWND h) +{ + HWND listbox = GetDlgItem (h, IDC_URL_LIST); + SendMessage (listbox, LB_SETCURSEL, list_idx, 0); + check_if_enable_next (h); +} + +static void +save_dialog (HWND h) +{ + HWND listbox = GetDlgItem (h, IDC_URL_LIST); + list_idx = SendMessage (listbox, LB_GETCURSEL, 0, 0); + if (list_idx == LB_ERR) + { + mirror_site = 0; + mirror_idx = NO_IDX; + list_idx = NO_IDX; + } + else + { + mirror_idx = SendMessage (listbox, LB_GETITEMDATA, list_idx, 0); + if (mirror_idx == OTHER_IDX) + mirror_site = 0; + else + mirror_site = site_list[mirror_idx].url; + } +} + +static void +get_root_dir () +{ + int issystem, isnative; + if (root_dir) + return; + root_dir = find_root_location (&issystem, &isnative); +} + +void +save_site_url () +{ + if (! MIRROR_SITE) + return; + + get_root_dir (); + if (! root_dir) + return; + + FILE *f = fopen (concat (root_dir, XEMACS_SETUP_DIR, "last-mirror", 0), "wb"); + if (!f) + return; + fprintf (f, "%s\n", MIRROR_SITE); + fclose (f); +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_URL_LIST: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDOK: + save_dialog (h); + if (mirror_idx == OTHER_IDX) + NEXT (IDD_OTHER_URL); + else + { + other_url = 0; + save_site_url (); + NEXT (IDD_S_LOAD_INI); + } + break; + + case IDC_BACK: + save_dialog (h); + NEXT (IDD_NET); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + int i, j; + HWND listbox; + switch (message) + { + case WM_INITDIALOG: + listbox = GetDlgItem (h, IDC_URL_LIST); + for (i=0; site_list[i].url; i++) + { + j = SendMessage (listbox, LB_ADDSTRING, 0, (LPARAM)site_list[i].displayed_url); + SendMessage (listbox, LB_SETITEMDATA, j, i); + } + j = SendMessage (listbox, LB_ADDSTRING, 0, (LPARAM)"Other URL"); + SendMessage (listbox, LB_SETITEMDATA, j, OTHER_IDX); + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +static int CDECL +site_sort (const void *va, const void *vb) +{ + site_list_type *a = (site_list_type *)va; + site_list_type *b = (site_list_type *)vb; + return strcmp (a->sort_key, b->sort_key); +} + +static int +get_site_list (HINSTANCE h) +{ + char mirror_url[1000]; + if (LoadString (h, IDS_MIRROR_LST, mirror_url, sizeof (mirror_url)) <= 0) + return 1; + char *mirrors = get_url_to_string (mirror_url); + dismiss_url_status_dialog (); + if (!mirrors) + return 1; + + char *bol, *eol, *nl; + + + /* null plus account for possibly missing NL plus account for "Other + URL" from previous run. */ + int nmirrors = 3; + + for (bol=mirrors; *bol; bol++) + if (*bol == '\n') + nmirrors ++; + + site_list = (site_list_type *) malloc (nmirrors * sizeof (site_list_type)); + nmirrors = 0; + + nl = mirrors; + while (*nl) + { + bol = nl; + for (eol = bol; *eol && *eol != '\n'; eol++) ; + if (*eol) + nl = eol+1; + else + nl = eol; + while (eol > bol && eol[-1] == '\r') + eol--; + *eol = 0; + if (bol[0] != '#' && bol[0] > ' ') + { + char *semi = strchr (bol, ';'); + if (semi) + *semi = 0; + site_list[nmirrors].url = _strdup (bol); + site_list[nmirrors].displayed_url = _strdup (bol); + char *dot = strchr (site_list[nmirrors].displayed_url, '.'); + if (dot) + { + dot = strchr (dot, '/'); + if (dot) + *dot = 0; + } + site_list[nmirrors].sort_key = (char *) malloc (2*strlen (bol) + 3); + + dot = site_list[nmirrors].displayed_url; + dot += strlen (dot); + char *dp = site_list[nmirrors].sort_key; + while (dot != site_list[nmirrors].displayed_url) + { + if (*dot == '.' || *dot == '/') + { + char *sp; + if (dot[3] == 0) + *dp++ = '~'; /* sort .com/.edu/.org together */ + for (sp=dot+1; *sp && *sp != '.' && *sp != '/';) + *dp++ = *sp++; + *dp++ = ' '; + } + dot--; + } + *dp++ = ' '; + strcpy (dp, site_list[nmirrors].displayed_url); + + nmirrors++; + } + } + site_list[nmirrors].url = 0; + + qsort (site_list, nmirrors, sizeof (site_list_type), site_sort); + + return 0; +} + +/* List of machines that should not be used by default when saved + in "last-mirror". */ +#define NOSAVE1 "ftp://ftp.xemacs.org/" +#define NOSAVE1_LEN (sizeof ("ftp://ftp.xemacs.org/") - 1) + +static void +get_initial_list_idx () +{ + get_root_dir (); + if (! root_dir) + return; + + FILE *f = fopen (concat (root_dir, XEMACS_SETUP_DIR, "last-mirror", 0), "rt"); + if (!f) + return; + + char site[1000]; + site[0]='\0'; + char * fg_ret = fgets (site, 1000, f); + fclose (f); + if (! fg_ret) + return; + + char *eos = site + strlen (site) - 1; + while (eos >= site && (*eos == '\n' || *eos == '\r')) + *eos-- = '\0'; + + if (eos < site) + return; + + int i; + for (i = 0; site_list[i].url; i++) + if (strcmp (site_list[i].url, site) == 0) + break; + + if (! site_list[i].url) + { + /* Don't default to certain machines ever since they suffer + from bandwidth limitations. */ + if (strnicmp (site, NOSAVE1, NOSAVE1_LEN) == 0) + return; + site_list[i].displayed_url = + site_list[i].url = _strdup (site); + site_list[i+1].url = 0; + } + + mirror_idx = list_idx = i; +} + +void +do_site (HINSTANCE h) +{ + int rv = 0; + + if (site_list == 0) + if (get_site_list (h)) + { + NEXT (IDD_NET); + return; + } + + get_initial_list_idx (); + + rv = DialogBox (h, MAKEINTRESOURCE (IDD_SITE), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); + + if (mirror_idx != OTHER_IDX) + log (0, "site: %s", mirror_site); +} + diff --git a/netinstall/source.cc b/netinstall/source.cc new file mode 100644 index 0000000..a1aa889 --- /dev/null +++ b/netinstall/source.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to manage the dialog box that lets the + user choose the source of the install - from the net, from the + current directory, or to just download files. */ + +#include "win32.h" +#include +#include "dialog.h" +#include "resource.h" +#include "state.h" +#include "msg.h" +#include "log.h" + +static int rb[] = { IDC_SOURCE_DOWNLOAD, IDC_SOURCE_NETINST, IDC_SOURCE_CWD, 0 }; + +static void +check_if_enable_next (HWND h) +{ + EnableWindow (GetDlgItem (h, IDOK), source ? 1 : 0); +} + +static void +load_dialog (HWND h) +{ + rbset (h, rb, source); + check_if_enable_next (h); +} + +static void +save_dialog (HWND h) +{ + source = rbget (h, rb); +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDC_SOURCE_DOWNLOAD: + case IDC_SOURCE_NETINST: + case IDC_SOURCE_CWD: + save_dialog (h); + check_if_enable_next (h); + break; + + case IDOK: + save_dialog (h); + NEXT (IDD_LOCAL_DIR); + break; + + case IDC_BACK: + save_dialog (h); + NEXT (0); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +void +do_source (HINSTANCE h) +{ + int rv = 0; + rv = DialogBox (h, MAKEINTRESOURCE (IDD_SOURCE), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); + + log (0, "source: %s", + (source == IDC_SOURCE_DOWNLOAD) ? "download" : + (source == IDC_SOURCE_NETINST) ? "network install" : "from cwd"); +} + diff --git a/netinstall/splash.cc b/netinstall/splash.cc new file mode 100644 index 0000000..9c866c7 --- /dev/null +++ b/netinstall/splash.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to display the program name, version, + copyright notice, and project URL. */ + +#include "win32.h" +#include +#include "dialog.h" +#include "resource.h" +#include "msg.h" +#include "version.h" + +static void +load_dialog (HWND h) +{ + char buffer[100]; + HWND v = GetDlgItem (h, IDC_VERSION); + sprintf (buffer, "Setup.exe version %s", + version[0] ? version : "[unknown]"); + SetWindowText (v, buffer); +} + +static BOOL +dialog_cmd (HWND h, int id, HWND hwndctl, UINT code) +{ + switch (id) + { + + case IDOK: + NEXT (IDD_SOURCE); + break; + + case IDCANCEL: + NEXT (0); + break; + } + return FALSE; +} + +static BOOL CALLBACK +dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + load_dialog (h); + return FALSE; + case WM_COMMAND: + return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd); + } + return FALSE; +} + +void +do_splash (HINSTANCE h) +{ + int rv = 0; + HANDLE gnu = LoadImage (h, MAKEINTRESOURCE (IDB_GNU), IMAGE_BITMAP, 0, 0, 0); + rv = DialogBox (h, MAKEINTRESOURCE (IDD_SPLASH), 0, dialog_proc); + if (rv == -1) + fatal (IDS_DIALOG_FAILED); +} + diff --git a/netinstall/state.cc b/netinstall/state.cc new file mode 100644 index 0000000..23502c2 --- /dev/null +++ b/netinstall/state.cc @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* All we do here is instantiate the extern'd variables from state.h */ + +#define extern +#include "state.h" diff --git a/netinstall/state.h b/netinstall/state.h new file mode 100644 index 0000000..6f11d78 --- /dev/null +++ b/netinstall/state.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to contain all the global variables + that define the "state" of the install, that is, all the + information that the user has provided so far. These are set by + the various dialogs and used by the various actions. */ + +extern int source; + +extern char * local_dir; + +extern char * root_dir; +extern int root_dir_default; +extern int install_type; +extern int root_scope; +extern int root_menu; +extern int root_desktop; + +extern int net_method; +extern char * net_proxy_host; +extern int net_proxy_port; + +extern char * net_user; +extern char * net_passwd; +extern char * net_proxy_user; +extern char * net_proxy_passwd; + +extern char * mirror_site; +extern char * other_url; + +extern int trust_level; + +#define MIRROR_SITE (mirror_site ? mirror_site : other_url) diff --git a/netinstall/tar.cc b/netinstall/tar.cc new file mode 100644 index 0000000..8be129e --- /dev/null +++ b/netinstall/tar.cc @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* Built-in tar functionality. See tar.h for usage. */ + +#include +#include +#include +#include + +#include "win32.h" +#include +#include "tar.h" +#include "mkdir.h" +#include "log.h" + +#include "port.h" + +#if defined(CYGWIN) || defined(MINGW) +#define FACTOR (0x19db1ded53ea710LL) +#define NSPERSEC 10000000LL +#else +__int64 FACTOR=0x19db1ded53ea710L; +__int64 NSPERSEC=10000000L; +#endif +#define SYMLINK_COOKIE "!" + +typedef struct { + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + char junk[12]; /* 500 */ +} tar_header_type; + +typedef struct tar_map_result_type_s { + struct tar_map_result_type_s *next; + char *stored_name; + char *mapped_name; +} tar_map_result_type; + +static tar_map_result_type *tar_map_result = 0; + +static int err; + +static char file_name[_MAX_PATH+512]; +static char have_longname = 0; +static int file_length; + +static tar_header_type tar_header; +static char buf[512]; + +static int _tar_file_size = 0; +int _tar_verbose = 0; +FILE * _tar_vfile = 0; +#define vp if (_tar_verbose) fprintf +#define vp2 if (_tar_verbose>1) fprintf + +static gzFile g = 0; + +static char * +xstrdup (char *c) +{ + char *r = (char *) malloc (strlen (c) + 1); + if (!r) + exit_setup (1); + strcpy (r, c); + return r; +} + +int +tar_open (char *pathname) +{ + struct stat s; + if (_tar_vfile == 0) + _tar_vfile = stderr; + + vp2 (_tar_vfile, "tar: open `%s'\n", pathname); + if (stat (pathname, &s) < 0) + return 1; + _tar_file_size = s.st_size; + + g = gzopen (pathname, "rb"); + if (sizeof (tar_header) != 512) + { + /* drastic, but important */ + fprintf (stderr, "compilation error: tar header struct not 512" + " bytes (it's %d)\n", sizeof (tar_header)); + exit_setup (1); + } + err = 0; + return g ? 0 : 1; +} + +int +tar_ftell () +{ + return gztell (g); +} + +static void +skip_file () +{ + while (file_length > 0) + { + gzread (g, buf, 512); + file_length -= 512; + } +} + +char * +tar_next_file () +{ + int r, n; + char *c; + r = gzread (g, &tar_header, 512); + + /* See if we're at end of file */ + if (r != 512) + return 0; + + /* See if the header is all zeros (i.e. last block) */ + n = 0; + for (r = 512/sizeof (int); r; r--) + n |= ((int *)&tar_header)[r-1]; + if (n == 0) + return 0; + + if (!have_longname && tar_header.typeflag != 'L') + { + memcpy (file_name, tar_header.name, 100); + file_name[100] = 0; + } + + sscanf (tar_header.size, "%o", &file_length); + + vp2 (_tar_vfile, "%c %9d %s\n", tar_header.typeflag, file_length, file_name); + + switch (tar_header.typeflag) + { + case 'L': /* GNU tar long name extension */ + if (file_length > _MAX_PATH) + { + skip_file (); + fprintf (stderr, "error: long file name exceeds %d characters\n", + _MAX_PATH); + err ++; + gzread (g, &tar_header, 512); + sscanf (tar_header.size, "%o", &file_length); + skip_file (); + return tar_next_file (); + } + c = file_name; + while (file_length > 0) + { + int need = file_length > 512 ? 512 : file_length; + if (gzread (g, buf, 512) < 512) + return 0; + memcpy (c, buf, need); + c += need; + file_length -= need; + } + *c = 0; + have_longname = 1; + return tar_next_file (); + + case '3': /* char */ + case '4': /* block */ + case '6': /* fifo */ + fprintf (stderr, "warning: not extracting special file %s\n", + file_name); + err ++; + return tar_next_file (); + + case '0': /* regular file */ + case 0: /* regular file also */ + case '2': /* symbolic link */ + case '5': /* directory */ + case '7': /* contiguous file */ + return file_name; + + case '1': /* hard link, we just copy */ + return file_name; + + default: + fprintf (stderr, "error: unknown (or unsupported) file type `%c'\n", + tar_header.typeflag); + err ++; + skip_file (); + return tar_next_file (); + } +} + +static void +fix_time_stamp (char *path) +{ + int mtime; +#if defined(CYGWIN) || defined(MINGW) + long long ftimev; +#else + __int64 ftimev; +#endif + FILETIME ftime; + HANDLE h; + + sscanf (tar_header.mtime, "%o", &mtime); + ftimev = mtime * NSPERSEC + FACTOR; + ftime.dwHighDateTime = ftimev >> 32; + ftime.dwLowDateTime = ftimev; + h = CreateFileA (path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); + if (h) + { + SetFileTime (h, 0, 0, &ftime); + CloseHandle (h); + } +} + +static FILE * +common_fopen (char *path) +{ + FILE *out; + out = fopen (path, "wb"); + if (!out) + { + /* maybe we need to create a directory */ + if (mkdir_p (0, path)) + { + skip_file (); + return 0; + } + out = fopen (path, "wb"); + } + if (!out) + { + fprintf (stderr, "unable to write to file %s\n", path); + perror ("The error was"); + skip_file (); + return 0; + } + return out; +} + +static void +prepare_for_file (char *path) +{ + DWORD w; + mkdir_p (0, path); + + w = GetFileAttributes (path); + if (w != 0xffffffff && w & FILE_ATTRIBUTE_DIRECTORY) + { + char *tmp = (char *) malloc (strlen (path) + 10); + int i = 0; + do { + i++; + sprintf (tmp, "%s.old-%d", path, i); + } while (GetFileAttributes (tmp) != 0xffffffff); + fprintf (stderr, "warning: moving directory \"%s\" out of the way.\n", path); + MoveFile (path, tmp); + free (tmp); + } + + DeleteFileA (path); +} + +int +tar_read_file (char *path) +{ + FILE *out, *copy; + HANDLE h; + DWORD w; + int got; + tar_map_result_type *tmr; + + switch (tar_header.typeflag) + { + case '0': /* regular files */ + case 0: + case '7': + vp (_tar_vfile, "F %s\n", path); + prepare_for_file (path); + out = common_fopen (path); + if (!out) + return 1; + + while (file_length > 0) + { + int put; + int want = file_length > 512 ? 512 : file_length; + got = gzread (g, buf, 512); + if (got < 512) + { + fprintf (stderr, "tar: unexpected end of file reading %s\n", path); + fclose (out); + remove (path); + return 1; + } + put = fwrite (buf, 1, want, out); + if (put < want) + { + fprintf (stderr, "tar: out of disk space writing %s\n", path); + fclose (out); + remove (path); + skip_file (); + return 1; + } + file_length -= want; + } + fclose (out); + + fix_time_stamp (path); + + /* we need this to do hard links below */ + tmr = (tar_map_result_type *) malloc (sizeof (tar_map_result_type)); + tmr->next = tar_map_result; + tmr->stored_name = xstrdup (file_name); + tmr->mapped_name = xstrdup (path); + tar_map_result = tmr; + + return 0; + + case '1': /* hard links; we just copy */ + for (tmr = tar_map_result; tmr; tmr=tmr->next) + if (strcmp (tmr->stored_name, tar_header.linkname) == 0) + break; + if (!tmr) + { + fprintf (stderr, "tar: can't find %s to link %s to\n", + tar_header.linkname, path); + return 1; + } + vp (_tar_vfile, "H %s <- %s\n", path, tmr->mapped_name); + prepare_for_file (path); + copy = fopen (tmr->mapped_name, "rb"); + if (!copy) + { + fprintf (stderr, "tar: unable to read %s\n", tmr->mapped_name); + return 1; + } + out = common_fopen (path); + if (!out) + return 1; + + while ((got = fread (buf, 1, 512, copy)) > 0) + { + int put = fwrite (buf, 1, got, out); + if (put < got) + { + fprintf (stderr, "tar: out of disk space writing %s\n", path); + fclose (out); + fclose (copy); + remove (path); + return 1; + } + } + fclose (out); + fclose (copy); + + fix_time_stamp (path); + return 0; + + case '5': /* directories */ + vp (_tar_vfile, "D %s\n", path); + while (path[0] && path[strlen (path)-1] == '/') + path[strlen (path) - 1] = 0; + return mkdir_p (1, path); + + + case '2': /* symbolic links */ + vp (_tar_vfile, "L %s -> %s\n", path, tar_header.linkname); + prepare_for_file (path); + h = CreateFileA (path, GENERIC_WRITE, 0, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, 0); + if (h == INVALID_HANDLE_VALUE) + { + fprintf (stderr, "error: unable to create symlink \"%s\" -> \"%s\"\n", + path, tar_header.linkname); + return 1; + } + strcpy (buf, SYMLINK_COOKIE); + strcat (buf, tar_header.linkname); + if (WriteFile (h, buf, strlen (buf) + 1, &w, NULL)) + { + CloseHandle (h); + SetFileAttributesA (path, FILE_ATTRIBUTE_SYSTEM); + return 0; + } + CloseHandle (h); + fprintf (stderr, "error: unable to write symlink \"%s\"\n", path); + DeleteFileA (path); + return 1; + } + + return 0; +} + +int +tar_close () +{ +#if 0 + while (tar_map_result) + { + tar_map_result_type *t = tar_map_result->next; + free (tar_map_result->stored_name); + free (tar_map_result->mapped_name); + free (tar_map_result); + tar_map_result = t; + } +#endif + tar_map_result = 0; + + if (gzclose (g)) + err ++; + return err; /* includes errors for skipped files, etc */ +} + +typedef struct { + char *from; + int from_len; + char *to; + int to_len; +} map_type; + +static map_type *map; +static int nmaps; + +int +tar_auto (char *pathname, char **maplist) +{ + char *c; + int errcount = 0; + int i, j; + map_type mtemp; + char newname[_MAX_PATH+512]; + static char twiddles[] = "|\b/\b-\b\\\b"; + int t = 0; + + for (nmaps=0; maplist[nmaps*2]; nmaps++) ; + map = (map_type *) malloc ((nmaps+1) * sizeof (map_type)); + for (nmaps=0; maplist[nmaps*2]; nmaps++) + { + map[nmaps].from = maplist[nmaps*2]; + map[nmaps].from_len = strlen (maplist[nmaps*2]); + map[nmaps].to = maplist[nmaps*2+1]; + map[nmaps].to_len = strlen (maplist[nmaps*2+1]); + } + /* bubble sort - expect the maps to be short */ + for (i=0; i= map[i].from_len + && strncmp (c, map[i].from, map[i].from_len) == 0) + { + strcpy (newname, map[i].to); + strcpy (newname+map[i].to_len, c + map[i].from_len); + c = newname; + break; + } + + t = (t+2) % 8; + fwrite (twiddles+t, 1, 2, stderr); + + if (tar_read_file (c)) + errcount ++; + } + if (tar_close ()) + errcount ++; + + fwrite (" \b", 1, 2, stderr); + + vp2 (_tar_vfile, "tar_auto returns %d\n", errcount); + return errcount; +} diff --git a/netinstall/tar.h b/netinstall/tar.h new file mode 100644 index 0000000..e299481 --- /dev/null +++ b/netinstall/tar.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +#ifndef __TAR_H_ +#define __TAR_H_ + +/* Only one tarfile may be open at a time. gzipped files handled + automatically */ + +/* returns zero on success, nonzero on failure */ +int tar_open (char *pathname); + +/* returns pointer to static buf containing name of next file */ +char * tar_next_file (); + +/* byte position in [compressed] file */ +int tar_ftell (); + +/* pass adjusted path, returns zero on success, nonzero on failure */ +int tar_read_file (char *path); + +/* closes the file */ +int tar_close (); + +/* pass path to tar file and from/to pairs for path prefix (NULLs at + end , returns zero if completely successful, nonzero (counts + errors) on failure */ +int tar_auto (char *pathname, char **map); + +int tar_mkdir_p (int isadir, char *path); + +/* +extern int _tar_verbose; +extern FILE * _tar_vfile; +*/ + +#endif diff --git a/netinstall/version.h b/netinstall/version.h new file mode 100644 index 0000000..9214dfd --- /dev/null +++ b/netinstall/version.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* misc version-related things */ + +extern "C" char *version; +extern "C" char *setup_version; +extern "C" unsigned int setup_timestamp; + +extern char *canonicalize_version (char *); diff --git a/netinstall/version.pl b/netinstall/version.pl new file mode 100644 index 0000000..60be739 --- /dev/null +++ b/netinstall/version.pl @@ -0,0 +1,6 @@ +while () { + if (/^\$Revision:\s*([0-9\.]*)/) { + print "char *version = \"$1\";\n"; + print "static char *id = \"\\n%%% setup-version $1\\n\";\n"; + } +} diff --git a/netinstall/win32.h b/netinstall/win32.h new file mode 100644 index 0000000..d1ee070 --- /dev/null +++ b/netinstall/win32.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to limit the number of Win32 headers we + actually have to parse. The Setup program only uses a few of them, + so there's no point in parsing them all (even lean-n-mean). Doing + this cuts compile time in half. */ + +#ifndef _MINI_WIN32_ +#define _MINI_WIN32_ + +#define _UNION_NAME(x) +#define _STRUCT_NAME(x) +#define NOCOMATTRIBUTE + +#include +#ifdef WIN32_NATIVE +/* MSVC is barking with the list above, something else is missing, so + I'm using and lean-n-mean. FP, 2000-23-12 */ +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Cope with native win32 & mingw differences. Written by F. Popineau + */ +#ifdef WIN32_NATIVE +# pragma warning( disable : 4007 4096 4018 4244 ) +# define strdup _strdup +# define stat _stat +# define strnicmp _strnicmp +#endif + +#ifndef CDECL +#define CDECL __cdecl +#endif + +#endif /* _MINI_WIN32_ */ diff --git a/netinstall/xemacs.ico b/netinstall/xemacs.ico new file mode 100644 index 0000000..b067330 Binary files /dev/null and b/netinstall/xemacs.ico differ diff --git a/tests/redisplay-tests.el b/tests/redisplay-tests.el new file mode 100644 index 0000000..1558ebe --- /dev/null +++ b/tests/redisplay-tests.el @@ -0,0 +1,42 @@ +;; Copyright (C) 2000 Free Software Foundation, Inc. + +;; Author: Yoshiki Hayashi +;; Maintainer: Yoshiki Hayashi +;; Created: 2000 +;; Keywords: tests + +;; This file is part of XEmacs. + +;; XEmacs 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, or (at your option) +;; any later version. + +;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +;;; Synched up with: Not in FSF. + +;;; Commentary: + +;; Redisplay related tests. + +;; This used to crash XEmacs. +(when (featurep 'mule) + (let ((buffer (generate-new-buffer "*split test*"))) + (set-window-buffer (selected-window) buffer) + (split-window-vertically) + (insert (make-char 'japanese-jisx0208 36 44)) + (backward-char) + (redraw-frame) + (delete-other-windows) + (split-window) + (kill-buffer buffer) + (delete-other-windows)))