Add a more generic mbox wrapper
[cygwin-setup.git] / localdir.cc
blobc83c041ab3abe502ec21073b901e8e58275375b9
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by Andrej Borsenkow <Andrej.Borsenkow@mow.siemens.ru>
13 * based on work and suggestions of DJ Delorie
17 /* The purpose of this file is to ask the user where they want the
18 * locally downloaded package files to be cached
21 #include "localdir.h"
23 #include "LogSingleton.h"
24 #include "LogFile.h"
25 #include "win32.h"
26 #include "filemanip.h"
28 #include <shlobj.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
33 #include "ini.h"
34 #include "dialog.h"
35 #include "resource.h"
36 #include "state.h"
37 #include "msg.h"
38 #include "mount.h"
39 #include "io_stream.h"
40 #include "mkdir.h"
42 #include "UserSettings.h"
44 #include "getopt++/StringOption.h"
46 #include "threebar.h"
47 extern ThreeBarProgressPage Progress;
49 static StringOption LocalDirOption ("", 'l', "local-package-dir", "Local package directory", false);
51 static ControlAdjuster::ControlInfo LocaldirControlsInfo[] = {
52 { IDC_LOCALDIR_GRP, CP_STRETCH, CP_TOP },
53 { IDC_LOCAL_DIR, CP_STRETCH, CP_TOP },
54 { IDC_LOCAL_DIR_BROWSE, CP_RIGHT, CP_TOP },
55 {0, CP_LEFT, CP_TOP}
58 LocalDirSetting::LocalDirSetting ()
60 const char *fg_ret;
61 if (std::string (LocalDirOption).size ())
62 local_dir = std::string (LocalDirOption);
63 else if ((fg_ret = UserSettings::instance().get ("last-cache")))
64 local_dir = std::string (fg_ret);
67 void
68 LocalDirSetting::save ()
70 UserSettings::instance().set ("last-cache", local_dir);
71 if (source == IDC_SOURCE_DOWNLOAD || !get_root_dir ().size())
73 const char *sep = isdirsep (local_dir[local_dir.size () - 1]) ? "" : "\\";
74 Logger ().clearFiles();
75 Logger ().setFile (LOG_BABBLE, local_dir + sep + "setup.log.full", false);
76 Logger ().setFile (0, local_dir + sep + "setup.log", true);
78 else
80 Logger ().clearFiles();
81 mkdir_p (1, cygpath ("/var/log").c_str (), 01777);
82 Logger ().setFile (LOG_BABBLE, cygpath ("/var/log/setup.log.full"),
83 false);
84 Logger ().setFile (0, cygpath ("/var/log/setup.log"), true);
88 static void
89 check_if_enable_next (HWND h)
91 EnableWindow (GetDlgItem (h, IDOK), local_dir.size() != 0);
94 static void
95 load_dialog (HWND h)
97 char descText[1000];
98 if (source != IDC_SOURCE_LOCALDIR)
100 LoadString (hinstance, IDS_LOCAL_DIR_DOWNLOAD, descText, sizeof (descText));
102 else
104 LoadString (hinstance, IDS_LOCAL_DIR_INSTALL, descText, sizeof (descText));
106 eset (h, IDC_LOCAL_DIR_DESC, descText);
107 eset (h, IDC_LOCAL_DIR, local_dir);
108 check_if_enable_next (h);
111 static void
112 save_dialog (HWND h)
114 local_dir = egetString (h, IDC_LOCAL_DIR);
117 // returns non-zero if refused or error, 0 if accepted and created ok.
118 static int
119 offer_to_create (HWND h, const char *dirname)
121 if (!dirname || !*dirname)
122 return -1;
124 if (!unattended_mode)
126 char msgText[MAX_PATH + 100];
127 char fmtString[100];
128 DWORD ret;
130 LoadString (hinstance, IDS_MAYBE_MKDIR, fmtString, sizeof fmtString);
131 snprintf (msgText, sizeof msgText, fmtString, dirname);
133 ret = MessageBox (h, msgText, "Cygwin Setup", MB_ICONSTOP | MB_YESNO);
134 if (ret == IDNO)
135 return -1;
138 int rv = mkdir_p (true, dirname, 0);
140 if (rv)
141 note (h, IDS_CANT_MKDIR, dirname);
143 return rv;
146 static int CALLBACK
147 browse_cb (HWND h, UINT msg, LPARAM lp, LPARAM data)
149 /* SHGetPathFromIDList doesn't handle path length > MAX_PATH. */
150 static CHAR dirname[MAX_PATH];
151 switch (msg)
153 case BFFM_INITIALIZED:
154 if (local_dir.size())
155 SendMessage (h, BFFM_SETSELECTION, TRUE, (LPARAM) local_dir.c_str());
156 break;
157 case BFFM_SELCHANGED:
159 // Make a note of each new dir we successfully select, so that
160 // we know where to create the new directory if an invalid name
161 // is entered in the text box.
162 LPITEMIDLIST pidl = reinterpret_cast<LPITEMIDLIST>(lp);
163 SHGetPathFromIDList (pidl, dirname);
164 break;
166 case BFFM_VALIDATEFAILED:
167 // See if user wants to create a dir in the last successfully-selected.
168 CHAR tempname[MAX_PATH];
169 snprintf (tempname, sizeof tempname, "%s\\%s", dirname, reinterpret_cast<LPTSTR>(lp));
170 if (!offer_to_create (h, tempname))
172 SendMessage (h, BFFM_SETSELECTION, TRUE, reinterpret_cast<LPARAM>(tempname));
173 return -1;
175 // Reset to original directory instead.
176 SendMessage (h, BFFM_SETSELECTION, TRUE, reinterpret_cast<LPARAM>(dirname));
177 return -1;
179 return 0;
182 static void
183 browse (HWND h)
185 BROWSEINFO bi;
186 /* SHGetPathFromIDList doesn't handle path length > MAX_PATH. */
187 CHAR name[MAX_PATH];
188 LPITEMIDLIST pidl;
189 memset (&bi, 0, sizeof (bi));
190 bi.hwndOwner = h;
191 bi.pszDisplayName = name;
192 bi.lpszTitle = (source != IDC_SOURCE_LOCALDIR) ? "Select download directory"
193 : "Select local package directory";
194 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE
195 | ((source != IDC_SOURCE_LOCALDIR) ? (BIF_EDITBOX | BIF_VALIDATE)
196 : 0);
197 bi.lpfn = browse_cb;
198 pidl = SHBrowseForFolder (&bi);
199 if (pidl)
201 if (SHGetPathFromIDList (pidl, name))
202 eset (h, IDC_LOCAL_DIR, name);
206 static BOOL
207 dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
209 switch (id)
212 case IDC_LOCAL_DIR:
213 save_dialog (h);
214 check_if_enable_next (h);
215 break;
217 case IDC_LOCAL_DIR_BROWSE:
218 browse (h);
219 break;
221 return 0;
224 LocalDirPage::LocalDirPage ()
226 sizeProcessor.AddControlInfo (LocaldirControlsInfo);
229 bool
230 LocalDirPage::Create ()
232 return PropertyPage::Create (NULL, dialog_cmd, IDD_LOCAL_DIR);
235 void
236 LocalDirPage::OnActivate ()
238 load_dialog (GetHWND ());
241 long
242 LocalDirPage::OnNext ()
244 HWND h = GetHWND ();
246 save_dialog (h);
247 while (local_dir[local_dir.size() - 1] == '\\' || local_dir[local_dir.size() - 1] == '/')
248 local_dir.erase (local_dir.size() - 1, 1);
249 LocalDirSetting::save ();
250 Log (LOG_PLAIN) << "Selected local directory: " << local_dir << endLog;
252 bool tryLocalDir = true;
253 while (tryLocalDir)
255 tryLocalDir = false;
256 /* FIXME: As for almost any other string, we should store local_dir
257 as UNICODE string to avoid the whole conversion mess.
258 We call GetFileAttributesW because our own version implies
259 FILE_OPEN_FOR_BACKUP_INTENT. We don't try to change CWD for
260 the same reason. */
261 size_t len = local_dir.size () + 7;
262 WCHAR wlocal[len];
263 mklongpath (wlocal, local_dir.c_str (), len);
264 DWORD attr = GetFileAttributesW (wlocal);
265 if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
267 if (source == IDC_SOURCE_LOCALDIR)
269 do_from_local_dir (GetInstance (), GetHWND (), local_dir);
270 Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD);
271 return IDD_INSTATUS;
274 else if (attr == INVALID_FILE_ATTRIBUTES
275 && (GetLastError () == ERROR_FILE_NOT_FOUND
276 || GetLastError () == ERROR_PATH_NOT_FOUND))
278 if (source == IDC_SOURCE_LOCALDIR)
280 if (!unattended_mode)
282 // Check the user really wants only to uninstall.
283 char msgText[1000];
284 LoadString (hinstance, IDS_NO_LOCALDIR, msgText,
285 sizeof (msgText));
286 char msg[1000 + local_dir.size ()];
287 snprintf (msg, sizeof (msg), msgText, local_dir.c_str ());
288 int ret = MessageBox (h, msg, "Cygwin Setup", MB_ICONEXCLAMATION | MB_OKCANCEL);
289 if (ret == IDCANCEL)
290 return -1;
292 Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD);
293 return IDD_INSTATUS;
295 else if (offer_to_create (GetHWND (), local_dir.c_str ()))
296 return -1;
297 tryLocalDir = true;
299 else
301 DWORD err = GetLastError ();
302 char msgText[1000];
303 LoadString (hinstance, IDS_ERR_CHDIR, msgText, sizeof (msgText));
304 char* buf;
305 char msg[1000];
306 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |
307 FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, err, LANG_NEUTRAL,
308 (LPSTR)&buf, 0, 0) != 0)
310 snprintf (msg, sizeof (msg), msgText, local_dir.c_str(),
311 buf, err);
312 LocalFree (buf);
314 else
315 snprintf (msg, sizeof (msg), msgText, local_dir.c_str(),
316 "(unknown error)", err);
317 int ret = mbox (h, msg, "Cygwin Setup", MB_ICONEXCLAMATION | MB_ABORTRETRYIGNORE);
318 if (ret == IDABORT)
319 return -1;
320 else
321 tryLocalDir = (ret == IDRETRY);
325 if (source == IDC_SOURCE_LOCALDIR)
326 return IDD_INSTATUS;
328 return 0; // IDD_NET
331 long
332 LocalDirPage::OnBack ()
334 save_dialog (GetHWND ());
335 return 0;