r323 - in trunk: . scripts
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Fri Jun 1 06:33:34 EDT 2007
Author: icculus
Date: 2007-06-01 06:33:34 -0400 (Fri, 01 Jun 2007)
New Revision: 323
Added:
trunk/gui_www.c
Modified:
trunk/CMakeLists.txt
trunk/gui.c
trunk/gui.h
trunk/scripts/localization.lua
Log:
Initial work on 'www' UI. Incomplete!
Modified: trunk/CMakeLists.txt
===================================================================
--- trunk/CMakeLists.txt 2007-06-01 10:33:05 UTC (rev 322)
+++ trunk/CMakeLists.txt 2007-06-01 10:33:34 UTC (rev 323)
@@ -374,7 +374,20 @@
ENDIF(NOT BEOS)
ENDIF(UNIX)
+# BINARY SIZE += !!! FIXME: check this.
+OPTION(MOJOSETUP_GUI_WWW "Enable www GUI" TRUE)
+IF(MOJOSETUP_GUI_WWW)
+ ADD_DEFINITIONS(-DSUPPORT_GUI_WWW=1)
+ OPTION(MOJOSETUP_GUI_WWW_STATIC "Statically link www GUI" TRUE)
+ IF(MOJOSETUP_GUI_WWW_STATIC)
+ ADD_DEFINITIONS(-DGUI_STATIC_LINK_WWW=1)
+ SET(OPTIONAL_SRCS ${OPTIONAL_SRCS} gui_www.c)
+ ELSE(MOJOSETUP_GUI_WWW_STATIC)
+ ADD_LIBRARY(mojosetupgui_www SHARED gui_www.c)
+ ENDIF(MOJOSETUP_GUI_WWW_STATIC)
+ENDIF(MOJOSETUP_GUI_WWW)
+
# Archivers...
# BINARY SIZE += 8
Modified: trunk/gui.c
===================================================================
--- trunk/gui.c 2007-06-01 10:33:05 UTC (rev 322)
+++ trunk/gui.c 2007-06-01 10:33:34 UTC (rev 323)
@@ -32,6 +32,9 @@
#if GUI_STATIC_LINK_GTKPLUS2
MojoGuiPlugin_gtkplus2,
#endif
+#if GUI_STATIC_LINK_WWW
+ MojoGuiPlugin_www,
+#endif
#if GUI_STATIC_LINK_NCURSES
MojoGuiPlugin_ncurses,
#endif
Modified: trunk/gui.h
===================================================================
--- trunk/gui.h 2007-06-01 10:33:05 UTC (rev 322)
+++ trunk/gui.h 2007-06-01 10:33:34 UTC (rev 323)
@@ -169,6 +169,7 @@
const MojoGui *MojoGuiPlugin_stdio(int rev, const MojoSetupEntryPoints *e);
const MojoGui *MojoGuiPlugin_ncurses(int rev, const MojoSetupEntryPoints *e);
const MojoGui *MojoGuiPlugin_gtkplus2(int rev, const MojoSetupEntryPoints *e);
+const MojoGui *MojoGuiPlugin_www(int rev, const MojoSetupEntryPoints *e);
const MojoGui *MojoGuiPlugin_macosx(int rev, const MojoSetupEntryPoints *e);
// !!! FIXME: Qt? KDE? Gnome? Console? Cocoa?
Added: trunk/gui_www.c
===================================================================
--- trunk/gui_www.c (rev 0)
+++ trunk/gui_www.c 2007-06-01 10:33:34 UTC (rev 323)
@@ -0,0 +1,906 @@
+/**
+ * MojoSetup; a portable, flexible installation application.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#if !SUPPORT_GUI_WWW
+#error Something is wrong in the build system.
+#endif
+
+#define BUILDING_EXTERNAL_PLUGIN 1
+#include "gui.h"
+
+MOJOGUI_PLUGIN(www)
+
+#if !GUI_STATIC_LINK_WWW
+CREATE_MOJOGUI_ENTRY_POINT(www)
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define FREE_AND_NULL(x) { free(x); x = NULL; }
+
+
+// tapdance between things WinSock and BSD Sockets define differently...
+#if PLATFORM_WINDOWS
+ #include <winsock.h>
+
+ typedef int socklen_t;
+
+ #define sockErrno() WSAGetLastError()
+ #define wouldBlockError(err) (err == WSAEWOULDBLOCK)
+ #define intrError(err) (err == WSAEINTR)
+
+ static inline void setBlocking(SOCKET s, boolean blocking)
+ {
+ u_long val = (blocking) ? 0 : 1;
+ ioctlsocket(s, FIONBIO, &val);
+ } // setBlocking
+
+ static const char *sockStrErrVal(int val)
+ {
+ STUBBED("Windows strerror");
+ } // sockStrErrVal
+
+
+ static boolean initSocketSupport(void)
+ {
+ WSADATA data;
+ int rc = WSAStartup(MAKEWORD(1, 1), &data);
+ if (rc != 0)
+ {
+ entry->logError("www: WSAStartup() failed: %s", sockStrErrVal(rc));
+ return false;
+ } // if
+
+ entry->logInfo("www: WinSock initialized (want %d.%d, got %d.%d).",
+ (int) (LOBYTE(data.wVersion)),
+ (int) (HIBYTE(data.wVersion)),
+ (int) (LOBYTE(data.wHighVersion)),
+ (int) (HIBYTE(data.wHighVersion)));
+ entry->logInfo("www: WinSock description: %s", data.szDescription);
+ entry->logInfo("www: WinSock system status: %s", data.szSystemStatus);
+ entry->logInfo("www: WinSock max sockets: %s", (int) data.iMaxSockets);
+
+ return true;
+ } // initSocketSupport
+
+ #define deinitSocketSupport() WSACleanup()
+
+#else
+ #include <unistd.h>
+ #include <errno.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <signal.h>
+ #include <netdb.h>
+ #include <fcntl.h>
+
+ typedef int SOCKET;
+
+ #define SOCKET_ERROR (-1)
+ #define INVALID_SOCKET (-1)
+ #define closesocket(x) close(x)
+ #define sockErrno() (errno)
+ #define sockStrErrVal(val) strerror(val)
+ #define intrError(err) (err == EINTR)
+ #define initSocketSupport() (true)
+ #define deinitSocketSupport()
+
+ static inline boolean wouldBlockError(int err)
+ {
+ return ((err == EWOULDBLOCK) || (err == EAGAIN));
+ } // wouldBlockError
+
+ static void setBlocking(SOCKET s, boolean blocking)
+ {
+ int flags = fcntl(s, F_GETFL, 0);
+ if (blocking)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+ fcntl(s, F_SETFL, flags);
+ } // setBlocking
+
+#endif
+
+#define sockStrError() (sockStrErrVal(sockErrno()))
+
+
+typedef struct _S_WebRequest
+{
+ char *key;
+ char *value;
+ struct _S_WebRequest *next;
+} WebRequest;
+
+
+static char *output = NULL;
+static char *lastProgressType = NULL;
+static char *lastComponent = NULL;
+static char *baseUrl = NULL;
+static WebRequest *webRequest = NULL;
+static uint32 percentTicks = 0;
+static SOCKET listenSocket = INVALID_SOCKET;
+static SOCKET clientSocket = INVALID_SOCKET;
+
+
+static uint8 MojoGui_www_priority(void)
+{
+ return MOJOGUI_PRIORITY_TRY_LAST;
+} // MojoGui_www_priority
+
+
+static void freeWebRequest(void)
+{
+ while (webRequest)
+ {
+ WebRequest *next = webRequest->next;
+ free(webRequest->key);
+ free(webRequest->value);
+ free(webRequest);
+ webRequest = next;
+ } // while
+} // freeWebRequest
+
+
+static void addWebRequest(const char *key, const char *val)
+{
+ if ((key != NULL) && (*key != '\0'))
+ {
+ WebRequest *req = (WebRequest *) entry->xmalloc(sizeof (WebRequest));
+ req->key = entry->xstrdup(key);
+ req->value = entry->xstrdup(val);
+ req->next = webRequest;
+ webRequest = req;
+ entry->logDebug("www: request element '%s' = '%s'", key, val);
+ } // if
+} // addWebRequest
+
+
+static int hexVal(char ch)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return (ch - 'a') + 16;
+ else if ((ch >= 'A') && (ch <= 'F'))
+ return (ch - 'A') + 16;
+ else if ((ch >= '0') && (ch <= '9'))
+ return (ch - '0');
+ return -1;
+} // hexVal
+
+
+static void unescapeUri(char *uri)
+{
+ char *ptr = uri;
+ while ((ptr = strchr(ptr, '%')) != NULL)
+ {
+ int a, b;
+ if ((a = hexVal(ptr[1])) != -1)
+ {
+ if ((b = hexVal(ptr[2])) != -1)
+ {
+ *(ptr++) = (char) ((a * 16) + b);
+ memmove(ptr, ptr+2, strlen(ptr+1));
+ } // if
+ else
+ {
+ *(ptr++) = '?';
+ memmove(ptr, ptr+1, strlen(ptr));
+ } // else
+ } // if
+ else
+ {
+ *(ptr++) = '?';
+ } // else
+ } // while
+} // unescapeUri
+
+
+static int strAdd(char **ptr, size_t *len, size_t *alloc, const char *fmt, ...)
+{
+ int bw = 0;
+ size_t avail = *alloc - *len;
+ va_list ap;
+ va_start(ap, fmt);
+ bw = vsnprintf(*ptr + *len, avail, fmt, ap);
+ va_end(ap);
+
+ if (bw >= avail)
+ {
+ const size_t add = (*alloc + (bw + 1)); // double plus the new len.
+ *alloc += add;
+ avail += add;
+ *ptr = entry->xrealloc(*ptr, *alloc);
+ va_start(ap, fmt);
+ bw = vsnprintf(*ptr + *len, avail, fmt, ap);
+ va_end(ap);
+ } // if
+
+ *len += bw;
+ return bw;
+} // strAdd
+
+
+static char *htmlescape(const char *str)
+{
+ size_t len = 0, alloc = 0;
+ char *retval = NULL;
+ char ch;
+
+ for (ch = *str; ch != '\0'; ch = *(str++))
+ {
+ switch (ch)
+ {
+ case '&': strAdd(&retval, &len, &alloc, "&"); break;
+ case '<': strAdd(&retval, &len, &alloc, "<"); break;
+ case '>': strAdd(&retval, &len, &alloc, ">"); break;
+ case '"': strAdd(&retval, &len, &alloc, """); break;
+ case '\'': strAdd(&retval, &len, &alloc, "'"); break;
+ default: strAdd(&retval, &len, &alloc, "%c", ch); break;
+ } // switch
+ } // while
+
+ return retval;
+} // htmlescape
+
+
+static const char *standardResponseHeaders =
+ "Content-Type: text/html; charset=utf-8\n"
+ "Accept-Ranges: none\n"
+ "Cache-Control: no-cache\n"
+ "Connection: close\n\n";
+
+
+static void setHtmlString(char **str, int responseCode,
+ const char *responseString,
+ const char *title, const char *html)
+{
+ size_t len = 0, alloc = 0;
+ FREE_AND_NULL(*str);
+ strAdd(str, &len, &alloc,
+ "HTTP/1.1 %d %s\n" // responseCode, responseString
+ "%s" // standardResponseHeaders
+ "<html>"
+ "<head>"
+ "<title>%s</title>" // title
+ "</head>"
+ "<body>%s</body>" // html
+ "</html>\n",
+ responseCode, responseString,
+ standardResponseHeaders,
+ title, html);
+} // setHtmlString
+
+
+static void setHtml(const char *title, const char *html)
+{
+ setHtmlString(&output, 200, "OK", title, html);
+} // setHtml
+
+
+static void sendStringAndDrop(SOCKET *_s, const char *str)
+{
+ SOCKET s = *_s;
+ int outlen = 0;
+ if (str == NULL)
+ str = "";
+ else
+ outlen = strlen(str);
+
+ setBlocking(s, true);
+
+ while (outlen > 0)
+ {
+ int rc = send(s, str, outlen, 0);
+ if (rc != SOCKET_ERROR)
+ {
+ str += rc;
+ outlen -= rc;
+ } // if
+ else
+ {
+ const int err = sockErrno();
+ if (!intrError(err))
+ {
+ entry->logError("www: send() failed: %s", sockStrErrVal(err));
+ break;
+ } // if
+ } // else
+ } // while
+
+ closesocket(s);
+ *_s = INVALID_SOCKET;
+} // sendStringAndDrop
+
+
+static void respond404(SOCKET *s)
+{
+ char *text = htmlescape(entry->_("Not Found"));
+ char *str = NULL;
+ size_t len = 0, alloc = 0;
+ char *html = NULL;
+ strAdd(&html, &len, &alloc, "<center><h1>%s</h1></center>", text);
+ setHtmlString(&str, 404, text, text, html);
+ free(html);
+ free(text);
+ sendStringAndDrop(s, str);
+ free(str);
+} // respond404
+
+
+static boolean parseGet(char *get)
+{
+ char *uri = NULL;
+ char *ver = NULL;
+
+ uri = strchr(get, ' ');
+ if (uri == NULL) return false;
+ *(uri++) = '\0';
+
+ ver = strchr(uri, ' ');
+ if (ver == NULL) return false;
+ *(ver++) = '\0';
+
+ if (strcmp(get, "GET") != 0) return false;
+ if (uri[0] != '/') return false;
+ uri++; // skip dirsep.
+
+ // !!! FIXME: we may want to feed stock files (<img> tags, etc)
+ // !!! FIXME: at some point in the future.
+ if ((uri[0] != '?') && (uri[0] != '\0')) return false;
+ if (strncmp(ver, "HTTP/", 5) != 0) return false;
+
+ if (*uri == '?')
+ uri++; // skip initial argsep.
+
+ do
+ {
+ char *next = strchr(uri, '&');
+ char *val = NULL;
+ if (next != NULL)
+ *(next++) = '\0';
+
+ val = strchr(uri, '=');
+ if (val == NULL)
+ val = "";
+ else
+ *(val++) = '\0';
+
+ unescapeUri(uri);
+ unescapeUri(val);
+ addWebRequest(uri, val);
+
+ uri = next;
+ } while (uri != NULL);
+
+ return true;
+} // parseGet
+
+
+static boolean parseRequest(char *reqstr)
+{
+ do
+ {
+ char *next = strchr(reqstr, '\n');
+ char *val = NULL;
+ if (next != NULL)
+ *(next++) = '\0';
+
+ val = strchr(reqstr, ':');
+ if (val == NULL)
+ val = "";
+ else
+ {
+ *(val++) = '\0';
+ while (*val == ' ')
+ val++;
+ } // else
+
+ if (*reqstr != '\0')
+ {
+ size_t len = 0, alloc = 0;
+ char *buf = NULL;
+ strAdd(&buf, &len, &alloc, "HTTP-%s", reqstr);
+ addWebRequest(buf, val);
+ free(buf);
+ } // if
+
+ reqstr = next;
+ } while (reqstr != NULL);
+
+ return true;
+} // parseRequest
+
+
+
+static WebRequest *servePage(boolean blocking)
+{
+ int newline = 0;
+ char ch = 0;
+ struct sockaddr_in addr;
+ socklen_t addrlen = 0;
+ int s = 0;
+ char *reqstr = NULL;
+ size_t len = 0, alloc = 0;
+ int err = 0;
+
+ freeWebRequest();
+
+ if (listenSocket == INVALID_SOCKET)
+ return NULL;
+
+ if (clientSocket != INVALID_SOCKET) // response to feed to client.
+ sendStringAndDrop(&clientSocket, output);
+
+ if (blocking)
+ setBlocking(listenSocket, true);
+
+ do
+ {
+ s = accept(listenSocket, (struct sockaddr *) &addr, &addrlen);
+ err = sockErrno();
+ } while ( (s == INVALID_SOCKET) && (intrError(err)) );
+
+ if (blocking)
+ setBlocking(listenSocket, false); // reset what we toggled up there.
+
+ if (s == INVALID_SOCKET)
+ {
+ if (wouldBlockError(err))
+ assert(!blocking);
+ else
+ {
+ entry->logError("www: accept() failed: %s", sockStrErrVal(err));
+ closesocket(listenSocket); // make all future i/o fail too.
+ listenSocket = INVALID_SOCKET;
+ } // else
+ return NULL;
+ } // if
+
+ setBlocking(s, true);
+
+ // Doing this one char at a time isn't efficient, but it's easy.
+
+ while (1)
+ {
+ if (recv(s, &ch, 1, 0) == SOCKET_ERROR)
+ {
+ const int err = sockErrno();
+ if (!intrError(err)) // just try again on interrupt.
+ {
+ entry->logError("www: recv() failed: %s", sockStrErrVal(err));
+ FREE_AND_NULL(reqstr);
+ closesocket(s);
+ s = INVALID_SOCKET;
+ break;
+ } // if
+ } // if
+
+ else if (ch == '\n') // newline
+ {
+ if (++newline == 2)
+ break; // end of request.
+ strAdd(&reqstr, &len, &alloc, "\n");
+ } // if
+
+ else if (ch != '\r')
+ {
+ newline = 0;
+ strAdd(&reqstr, &len, &alloc, "%c", ch);
+ } // else if
+ } // while
+
+ if (reqstr != NULL)
+ {
+ char *get = NULL;
+ char *ptr = strchr(reqstr, '\n');
+ if (ptr != NULL)
+ {
+ *ptr = '\0';
+ ptr++;
+ } // if
+
+ // reqstr is the GET (or whatever) request, ptr is the rest.
+ get = entry->xstrdup(reqstr);
+ if (ptr == NULL)
+ {
+ *ptr = '\0';
+ len = 0;
+ } // if
+ else
+ {
+ len = strlen(ptr);
+ memmove(reqstr, ptr, len+1);
+ } // else
+
+ entry->logDebug("www: request '%s'", get);
+
+ // okay, now (get) and (reqptr) are separate strings.
+ // These parse*() functions update (webRequest).
+ if ( (parseGet(get)) && (parseRequest(reqstr)) )
+ entry->logDebug("www: accepted request");
+ else
+ {
+ entry->logError("www: rejected bogus request");
+ freeWebRequest();
+ respond404(&s);
+ } // else
+
+ free(reqstr);
+ free(get);
+ } // if
+
+ clientSocket = s;
+ return webRequest;
+} // servePage
+
+
+static SOCKET create_listen_socket(short portnum)
+{
+ SOCKET s = INVALID_SOCKET;
+ int protocol = 0; // pray this is right.
+ struct protoent *prot;
+
+ setprotoent(0);
+ prot = getprotobyname("tcp");
+ if (prot != NULL)
+ protocol = prot->p_proto;
+
+ s = socket(PF_INET, SOCK_STREAM, protocol);
+ if (s == INVALID_SOCKET)
+ entry->logInfo("www: socket() failed ('%s')", sockStrError());
+ else
+ {
+ boolean success = false;
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(portnum);
+ addr.sin_addr.s_addr = INADDR_ANY; // !!! FIXME: bind to localhost.
+ if (bind(s, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
+ entry->logError("www: bind() failed ('%s')", sockStrError());
+ else if (listen(s, 5) == SOCKET_ERROR)
+ entry->logError("www: listen() failed ('%s')", sockStrError());
+ else
+ {
+ entry->logInfo("www: socket created on port %d", (int) portnum);
+ success = true;
+ } // else
+
+ if (!success)
+ {
+ closesocket(s);
+ s = INVALID_SOCKET;
+ } // if
+ } // if
+
+ return s;
+} // create_listen_socket
+
+
+static boolean MojoGui_www_init(void)
+{
+ size_t len = 0, alloc = 0;
+ short portnum = 7341; // !!! FIXME: try some random ports.
+ percentTicks = 0;
+
+ if (!initSocketSupport())
+ {
+ entry->logInfo("www: socket subsystem init failed, use another UI.");
+ return false;
+ } // if
+
+ listenSocket = create_listen_socket(portnum);
+ if (listenSocket < 0)
+ {
+ entry->logInfo("www: no listen socket, use another UI.");
+ return false;
+ } // if
+
+ setBlocking(listenSocket, false);
+
+ strAdd(&baseUrl, &len, &alloc, "http://localhost:%d/", (int) portnum);
+ return true;
+} // MojoGui_www_init
+
+
+static void MojoGui_www_deinit(void)
+{
+ // Catch any waiting browser connections...and tell them to buzz off! :)
+ char *donetitle = htmlescape(entry->_("Shutting down..."));
+ char *donetext = htmlescape(entry->_(
+ "Setup program is shutting down. You can close this browser now."));
+ size_t len = 0, alloc = 0;
+ char *html = NULL;
+
+ strAdd(&html, &len, &alloc, "<center><h1>%s</h1></center>", donetext);
+ setHtml(donetitle, html);
+ free(html);
+ free(donetitle);
+ free(donetext);
+ while (servePage(false) != NULL) { /* no-op. */ }
+
+ freeWebRequest();
+ FREE_AND_NULL(output);
+ FREE_AND_NULL(lastProgressType);
+ FREE_AND_NULL(lastComponent);
+ FREE_AND_NULL(baseUrl);
+
+ if (clientSocket != INVALID_SOCKET)
+ {
+ closesocket(clientSocket);
+ clientSocket = INVALID_SOCKET;
+ } // if
+
+ if (listenSocket != INVALID_SOCKET)
+ {
+ closesocket(listenSocket);
+ listenSocket = INVALID_SOCKET;
+ } // if
+
+ deinitSocketSupport();
+} // MojoGui_www_deinit
+
+
+static int doPromptPage(const char *title, const char *text,
+ const char *pagename,
+ const char **buttons, const char **localizedButtons,
+ int bcount)
+{
+ char *htmltitle = htmlescape(title);
+ boolean sawPage = false;
+ int answer = -1;
+ int i = 0;
+ char *html = NULL;
+ size_t len = 0, alloc = 0;
+
+ strAdd(&html, &len, &alloc,
+ "<center>"
+ "<form name='form_%s' method='get'>" // pagename
+ "<input type='hidden' name='page' value='%s'>" // pagename
+ "<table>"
+ "<tr><td align='center'>%s</td></tr>" // text
+ "<tr>"
+ "<td align='center'>", pagename, pagename, text);
+
+ for (i = 0; i < bcount; i++)
+ {
+ const char *button = buttons[i];
+ const char *loc = localizedButtons[i];
+ strAdd(&html, &len, &alloc,
+ "<input type='submit' name='%s' value='%s'>", button, loc);
+ } // for
+
+ strAdd(&html, &len, &alloc,
+ "</td>"
+ "</tr>"
+ "</table>"
+ "</form>"
+ "</center>");
+
+ setHtml(htmltitle, html);
+ free(htmltitle);
+ free(html);
+
+ while ((!sawPage) || (answer == -1))
+ {
+ WebRequest *req = servePage(true);
+ sawPage = false;
+ answer = -1;
+ while (req != NULL)
+ {
+ const char *k = req->key;
+ const char *v = req->value;
+ if ( (strcmp(k, "page") == 0) && (strcmp(v, pagename) == 0) )
+ sawPage = true;
+ else
+ {
+ for (i = 0; i < bcount; i++)
+ {
+ if (strcmp(k, buttons[i]) == 0)
+ {
+ answer = i;
+ break;
+ } // if
+ } // for
+ } // else
+
+ req = req->next;
+ } // for
+ } // while
+
+ return answer;
+} // doPromptPage
+
+
+static void MojoGui_www_msgbox(const char *title, const char *text)
+{
+ char *buttons[] = { "ok" };
+ char *localizedButtons[] = { htmlescape(entry->_("OK")) };
+ char *htmltext = htmlescape(text);
+ doPromptPage(title, htmltext, "msgbox", buttons, localizedButtons, 1);
+ free(htmltext);
+ free(localizedButtons[0]);
+} // MojoGui_www_msgbox
+
+
+static boolean MojoGui_www_promptyn(const char *title, const char *text)
+{
+ int i, rc;
+ char *htmltext = htmlescape(text);
+ char *buttons[] = { "no", "yes" };
+ char *localizedButtons[] = {
+ htmlescape(entry->_("No"))
+ htmlescape(entry->_("Yes")),
+ };
+ assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(localizedButtons));
+
+ rc = doPromptPage(title, htmltext, "promptyn", buttons, localizedButtons,
+ STATICARRAYLEN(buttons));
+ free(htmltext);
+
+ for (i = 0; i < STATICARRAYLEN(localizedButtons); i++)
+ free(localizedButtons[i]);
+
+ return (rc == 1);
+} // MojoGui_www_promptyn
+
+
+static MojoGuiYNAN MojoGui_www_promptynan(const char *title, const char *txt)
+{
+ int i, rc;
+ char *htmltext = htmlescape(text);
+ char *buttons[] = { "no", "yes", "always", "never" };
+ char *localizedButtons[] = {
+ htmlescape(entry->_("No"))
+ htmlescape(entry->_("Yes")),
+ htmlescape(entry->_("Always")),
+ htmlescape(entry->_("Never")),
+ };
+ assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(localizedButtons));
+
+ rc = doPromptPage(title, htmltext, "promptynan", buttons, localizedButtons,
+ STATICARRAYLEN(buttons));
+
+ free(htmltext);
+ for (i = 0; i < STATICARRAYLEN(localizedButtons); i++)
+ free(localizedButtons[i]);
+
+ return (MojoGuiYNAN) rc;
+} // MojoGui_www_promptynan
+
+
+static boolean MojoGui_www_start(const char *title, const char *splash)
+{
+ return true;
+} // MojoGui_www_start
+
+
+static void MojoGui_www_stop(void)
+{
+ // no-op.
+} // MojoGui_www_stop
+
+
+static int MojoGui_www_readme(const char *name, const uint8 *data,
+ size_t datalen, boolean can_back,
+ boolean can_fwd)
+{
+ char *text = NULL;
+ size_t len = 0, alloc = 0;
+ char *htmldata = htmlescape(data);
+ int i, rc;
+ int cancelbutton = -1;
+ int backbutton = -1;
+ int fwdbutton = -1;
+ int bcount = 0;
+ char *buttons[4] = { NULL, NULL, NULL, NULL };
+ char *localizedButtons[4] = { NULL, NULL, NULL, NULL };
+ assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(localizedButtons));
+
+ cancelbutton = bcount++;
+ buttons[cancelbutton] = "next";
+ localizedButtons[cancelbutton] = entry->xstrdup(entry->_("Cancel"));
+
+ if (can_back)
+ {
+ backbutton = bcount++;
+ buttons[backbutton] = "back";
+ localizedButtons[backbutton] = entry->xstrdup(entry->_("Back"));
+ } // if
+
+ if (can_fwd)
+ {
+ fwdbutton = bcount++;
+ buttons[fwdbutton] = "next";
+ localizedButtons[fwdbutton] = entry->xstrdup(entry->_("Next"));
+ } // if
+
+ strAdd(&text, &len, &alloc, "<pre>\n%s\n</pre>", htmldata);
+ free(htmldata);
+
+ rc = doPromptPage(name, text, "readme", buttons, localizedButtons, bcount);
+
+ free(text);
+ for (i = 0; i < STATICARRAYLEN(localizedButtons); i++)
+ free(localizedButtons[i]);
+
+ if (rc == backbutton)
+ return -1;
+ else if (rc == cancelbutton)
+ return 0;
+ return 1;
+} // MojoGui_www_readme
+
+
+static int MojoGui_www_options(MojoGuiSetupOptions *opts,
+ boolean can_back, boolean can_fwd)
+{
+ return 1;
+} // MojoGui_www_options
+
+
+static char *MojoGui_www_destination(const char **recommends, int recnum,
+ int *command, boolean can_back,
+ boolean can_fwd)
+{
+ *command = 0;
+ return NULL;
+} // MojoGui_www_destination
+
+
+static boolean MojoGui_www_insertmedia(const char *medianame)
+{
+ char *htmltext = NULL;
+ char *text = NULL;
+ size_t len = 0, alloc = 0;
+
+ // !!! FIXME: better text.
+ const char *title = entry->xstrdup(entry->_("Media change"));
+ // !!! FIXME: better text.
+ strAdd(&text, &len, &alloc, entry->_("Please insert '%s'"), medianame);
+
+ htmltext = htmlescape(text);
+ free(text);
+
+ int i, rc;
+ char *buttons[] = { "cancel", "ok" };
+ char *localizedButtons[] = {
+ htmlescape(entry->_("Cancel"))
+ htmlescape(entry->_("OK")),
+ };
+ assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(localizedButtons));
+
+ rc = doPromptPage(title, htmltext, "insertmedia", buttons,
+ localizedButtons, STATICARRAYLEN(buttons));
+
+ free(title);
+ free(htmltext);
+ for (i = 0; i < STATICARRAYLEN(localizedButtons); i++)
+ free(localizedButtons[i]);
+
+ return (rc == 1);
+} // MojoGui_www_insertmedia
+
+
+static boolean MojoGui_www_progress(const char *type, const char *component,
+ int percent, const char *item)
+{
+ return true;
+} // MojoGui_www_progress
+
+
+static void MojoGui_www_final(const char *msg)
+{
+} // MojoGui_www_final
+
+// end of gui_www.c ...
+
Modified: trunk/scripts/localization.lua
===================================================================
--- trunk/scripts/localization.lua 2007-06-01 10:33:05 UTC (rev 322)
+++ trunk/scripts/localization.lua 2007-06-01 10:33:34 UTC (rev 323)
@@ -142,6 +142,17 @@
["(I want to specify a path.)"] = {
};
+
+ -- as in "404 Not Found" in a web browser.
+ ["Not Found"] = {
+ };
+
+ -- title bar in browser page, used with next item for page's text.
+ ["Shutting down..."] = {
+ };
+
+ ["Setup program is shutting down. You can close this browser now."] = {
+ };
};
-- end of localization.lua ...
More information about the mojosetup-commits
mailing list