mirror of
https://github.com/glest/glest-source.git
synced 2025-02-25 04:02:30 +01:00
1117 lines
28 KiB
C
1117 lines
28 KiB
C
/**
|
|
* 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 <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 setprotoent(x) assert(x == 0)
|
|
#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");
|
|
return "sockStrErrVal() is unimplemented.";
|
|
} // sockStrErrVal
|
|
|
|
|
|
static boolean initSocketSupport(void)
|
|
{
|
|
WSADATA data;
|
|
int rc = WSAStartup(MAKEWORD(1, 1), &data);
|
|
if (rc != 0)
|
|
{
|
|
logError("www: WSAStartup() failed: %0", sockStrErrVal(rc));
|
|
return false;
|
|
} // if
|
|
|
|
logInfo("www: WinSock initialized (want %0.%1, got %2.%3).",
|
|
numstr((int) (LOBYTE(data.wVersion))),
|
|
numstr((int) (HIBYTE(data.wVersion))),
|
|
numstr((int) (LOBYTE(data.wHighVersion))),
|
|
numstr((int) (HIBYTE(data.wHighVersion))));
|
|
logInfo("www: WinSock description: %0", data.szDescription);
|
|
logInfo("www: WinSock system status: %0", data.szSystemStatus);
|
|
logInfo("www: WinSock max sockets: %0", numstr((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(boolean istty)
|
|
{
|
|
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 *) xmalloc(sizeof (WebRequest));
|
|
req->key = xstrdup(key);
|
|
req->value = xstrdup(val);
|
|
req->next = webRequest;
|
|
webRequest = req;
|
|
logDebug("www: request element '%0' = '%1'", key, val);
|
|
} // if
|
|
} // addWebRequest
|
|
|
|
|
|
static int hexVal(char ch)
|
|
{
|
|
if ((ch >= 'a') && (ch <= 'f'))
|
|
return (ch - 'a') + 10;
|
|
else if ((ch >= 'A') && (ch <= 'F'))
|
|
return (ch - 'A') + 10;
|
|
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, ...)
|
|
{
|
|
size_t 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 = 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;
|
|
|
|
while ((ch = *(str++)) != '\0')
|
|
{
|
|
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))
|
|
{
|
|
logError("www: send() failed: %0", sockStrErrVal(err));
|
|
break;
|
|
} // if
|
|
} // else
|
|
} // while
|
|
|
|
closesocket(s);
|
|
*_s = INVALID_SOCKET;
|
|
} // sendStringAndDrop
|
|
|
|
|
|
static void respond404(SOCKET *s)
|
|
{
|
|
char *text = htmlescape(_("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
|
|
{
|
|
logError("www: accept() failed: %0", 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.
|
|
{
|
|
logError("www: recv() failed: %0", 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 = xstrdup(reqstr);
|
|
if (ptr == NULL)
|
|
{
|
|
*ptr = '\0';
|
|
len = 0;
|
|
} // if
|
|
else
|
|
{
|
|
len = strlen(ptr);
|
|
memmove(reqstr, ptr, len+1);
|
|
} // else
|
|
|
|
logDebug("www: request '%0'", get);
|
|
|
|
// okay, now (get) and (reqptr) are separate strings.
|
|
// These parse*() functions update (webRequest).
|
|
if ( (parseGet(get)) && (parseRequest(reqstr)) )
|
|
logDebug("www: accepted request");
|
|
else
|
|
{
|
|
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)
|
|
logInfo("www: socket() failed ('%0')", 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.
|
|
|
|
// So we can bind this socket over and over in debug runs...
|
|
#if ((!defined _NDEBUG) && (!defined NDEBUG))
|
|
{
|
|
int on = 1;
|
|
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &on, sizeof (on));
|
|
}
|
|
#endif
|
|
|
|
if (bind(s, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
|
|
logError("www: bind() failed ('%0')", sockStrError());
|
|
else if (listen(s, 5) == SOCKET_ERROR)
|
|
logError("www: listen() failed ('%0')", sockStrError());
|
|
else
|
|
{
|
|
logInfo("www: socket created on port %0",
|
|
numstr(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())
|
|
{
|
|
logInfo("www: socket subsystem init failed, use another UI.");
|
|
return false;
|
|
} // if
|
|
|
|
listenSocket = create_listen_socket(portnum);
|
|
if (listenSocket < 0)
|
|
{
|
|
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(_("Shutting down..."));
|
|
char *donetext = htmlescape(_("You can close this browser now."));
|
|
size_t len = 0, alloc = 0;
|
|
char *html = NULL;
|
|
|
|
strAdd(&html, &len, &alloc, "<hr><center>%s</center><hr>", 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, boolean centertxt,
|
|
const char *pagename,
|
|
const char **buttons, const char **locButtons,
|
|
int bcount)
|
|
{
|
|
char *htmltitle = htmlescape(title);
|
|
boolean sawPage = false;
|
|
int answer = -1;
|
|
int i = 0;
|
|
char *html = NULL;
|
|
size_t len = 0, alloc = 0;
|
|
const char *align = ((centertxt) ? " align='center'" : "");
|
|
|
|
strAdd(&html, &len, &alloc,
|
|
"<center>"
|
|
"<form name='form_%s' method='get'>" // pagename
|
|
"<input type='hidden' name='page' value='%s'>" // pagename
|
|
"<table>"
|
|
"<tr><td%s>%s</td></tr>" // align, text
|
|
"<tr>"
|
|
"<td align='center'>", pagename, pagename, align, text);
|
|
|
|
for (i = 0; i < bcount; i++)
|
|
{
|
|
const char *button = buttons[i];
|
|
const char *loc = locButtons[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;
|
|
} // while
|
|
} // while
|
|
|
|
return answer;
|
|
} // doPromptPage
|
|
|
|
|
|
static void MojoGui_www_msgbox(const char *title, const char *text)
|
|
{
|
|
const char *buttons[] = { "ok" };
|
|
const char *locButtons[] = { htmlescape(_("OK")) };
|
|
char *htmltext = htmlescape(text);
|
|
doPromptPage(title, htmltext, true, "msgbox", buttons, locButtons, 1);
|
|
free(htmltext);
|
|
free((void *) locButtons[0]);
|
|
} // MojoGui_www_msgbox
|
|
|
|
|
|
static boolean MojoGui_www_promptyn(const char *title, const char *text,
|
|
boolean defval)
|
|
{
|
|
// !!! FIXME:
|
|
// We currently ignore defval
|
|
|
|
int i, rc;
|
|
char *htmltext = htmlescape(text);
|
|
const char *buttons[] = { "no", "yes" };
|
|
const char *locButtons[] = { htmlescape(_("No")), htmlescape(_("Yes")) };
|
|
|
|
assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(locButtons));
|
|
|
|
rc = doPromptPage(title, htmltext, true, "promptyn", buttons, locButtons,
|
|
STATICARRAYLEN(buttons));
|
|
free(htmltext);
|
|
|
|
for (i = 0; i < STATICARRAYLEN(locButtons); i++)
|
|
free((void *) locButtons[i]);
|
|
|
|
return (rc == 1);
|
|
} // MojoGui_www_promptyn
|
|
|
|
|
|
static MojoGuiYNAN MojoGui_www_promptynan(const char *title, const char *text,
|
|
boolean defval)
|
|
{
|
|
// !!! FIXME:
|
|
// We currently ignore defval
|
|
|
|
int i, rc;
|
|
char *htmltext = htmlescape(text);
|
|
const char *buttons[] = { "no", "yes", "always", "never" };
|
|
const char *locButtons[] = {
|
|
htmlescape(_("No")),
|
|
htmlescape(_("Yes")),
|
|
htmlescape(_("Always")),
|
|
htmlescape(_("Never")),
|
|
};
|
|
assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(locButtons));
|
|
|
|
rc = doPromptPage(title, htmltext, true, "promptynan", buttons, locButtons,
|
|
STATICARRAYLEN(buttons));
|
|
|
|
free(htmltext);
|
|
for (i = 0; i < STATICARRAYLEN(locButtons); i++)
|
|
free((void *) locButtons[i]);
|
|
|
|
return (MojoGuiYNAN) rc;
|
|
} // MojoGui_www_promptynan
|
|
|
|
|
|
static boolean MojoGui_www_start(const char *title,
|
|
const MojoGuiSplash *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((const char *) data);
|
|
int i, rc;
|
|
int cancelbutton = -1;
|
|
int backbutton = -1;
|
|
int fwdbutton = -1;
|
|
int bcount = 0;
|
|
const char *buttons[4] = { NULL, NULL, NULL, NULL };
|
|
const char *locButtons[4] = { NULL, NULL, NULL, NULL };
|
|
assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(locButtons));
|
|
|
|
cancelbutton = bcount++;
|
|
buttons[cancelbutton] = "cancel";
|
|
locButtons[cancelbutton] = xstrdup(_("Cancel"));
|
|
|
|
if (can_back)
|
|
{
|
|
backbutton = bcount++;
|
|
buttons[backbutton] = "back";
|
|
locButtons[backbutton] = xstrdup(_("Back"));
|
|
} // if
|
|
|
|
if (can_fwd)
|
|
{
|
|
fwdbutton = bcount++;
|
|
buttons[fwdbutton] = "next";
|
|
locButtons[fwdbutton] = xstrdup(_("Next"));
|
|
} // if
|
|
|
|
strAdd(&text, &len, &alloc, "<pre>\n%s\n</pre>", htmldata);
|
|
free(htmldata);
|
|
|
|
rc = doPromptPage(name, text, false, "readme", buttons, locButtons, bcount);
|
|
|
|
free(text);
|
|
for (i = 0; i < STATICARRAYLEN(locButtons); i++)
|
|
free((void *) locButtons[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)
|
|
{
|
|
// !!! FIXME: write me.
|
|
STUBBED("www options");
|
|
return 1;
|
|
} // MojoGui_www_options
|
|
|
|
|
|
static char *MojoGui_www_destination(const char **recommends, int recnum,
|
|
int *command, boolean can_back,
|
|
boolean can_fwd)
|
|
{
|
|
char *retval = NULL;
|
|
char *title = xstrdup(_("Destination"));
|
|
char *html = NULL;
|
|
size_t len = 0, alloc = 0;
|
|
boolean checked = true;
|
|
int cancelbutton = -1;
|
|
int backbutton = -1;
|
|
int fwdbutton = -1;
|
|
int bcount = 0;
|
|
int rc = 0;
|
|
int i = 0;
|
|
const char *buttons[4] = { NULL, NULL, NULL, NULL };
|
|
const char *locButtons[4] = { NULL, NULL, NULL, NULL };
|
|
assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(locButtons));
|
|
|
|
cancelbutton = bcount++;
|
|
buttons[cancelbutton] = "cancel";
|
|
locButtons[cancelbutton] = xstrdup(_("Cancel"));
|
|
|
|
if (can_back)
|
|
{
|
|
backbutton = bcount++;
|
|
buttons[backbutton] = "back";
|
|
locButtons[backbutton] = xstrdup(_("Back"));
|
|
} // if
|
|
|
|
if (can_fwd)
|
|
{
|
|
fwdbutton = bcount++;
|
|
buttons[fwdbutton] = "next";
|
|
locButtons[fwdbutton] = xstrdup(_("Next"));
|
|
} // if
|
|
|
|
strAdd(&html, &len, &alloc,
|
|
"<form name='form_destination' method='get'>"
|
|
"<table>");
|
|
|
|
for (i = 0; i < recnum; i++)
|
|
{
|
|
strAdd(&html, &len, &alloc,
|
|
"<tr>"
|
|
"<td>"
|
|
"<input type='radio' name='dest' %s value='%s'>%s"
|
|
"</td>"
|
|
"</tr>",
|
|
((checked) ? "checked='true'" : ""), recommends[i], recommends[i]);
|
|
checked = false;
|
|
} // for
|
|
|
|
strAdd(&html, &len, &alloc,
|
|
"<tr>"
|
|
"<td>"
|
|
"<input type='radio' name='dest' %s value='*'>"
|
|
"<input type='text' name='customdest' value=''>"
|
|
"</td>"
|
|
"</tr>"
|
|
"</table>"
|
|
"</form>", ((checked) ? "checked='true'" : ""));
|
|
|
|
rc = doPromptPage(title, html, true, "destination",
|
|
buttons, locButtons, bcount);
|
|
|
|
free(title);
|
|
free(html);
|
|
for (i = 0; i < STATICARRAYLEN(locButtons); i++)
|
|
free((void *) locButtons[i]);
|
|
|
|
if (rc == backbutton)
|
|
*command = -1;
|
|
else if (rc == cancelbutton)
|
|
*command = 0;
|
|
else
|
|
{
|
|
const char *dest = NULL;
|
|
const char *customdest = NULL;
|
|
WebRequest *req = webRequest;
|
|
while (req != NULL)
|
|
{
|
|
const char *k = req->key;
|
|
const char *v = req->value;
|
|
if (strcmp(k, "dest") == 0)
|
|
dest = v;
|
|
else if (strcmp(k, "customdest") == 0)
|
|
customdest = v;
|
|
req = req->next;
|
|
} // while
|
|
|
|
if (dest != NULL)
|
|
{
|
|
if (strcmp(dest, "*") == 0)
|
|
dest = customdest;
|
|
} // if
|
|
|
|
if (dest == NULL)
|
|
*command = 0; // !!! FIXME: maybe loop with doPromptPage again.
|
|
else
|
|
{
|
|
retval = xstrdup(dest);
|
|
*command = 1;
|
|
} // else
|
|
} // else
|
|
|
|
return retval;
|
|
} // MojoGui_www_destination
|
|
|
|
|
|
static int MojoGui_www_productkey(const char *desc, const char *fmt,
|
|
char *buf, const int buflen,
|
|
boolean can_back, boolean can_fwd)
|
|
{
|
|
char *prompt = xstrdup(_("Please enter your product key"));
|
|
int retval = -1;
|
|
char *html = NULL;
|
|
size_t len = 0, alloc = 0;
|
|
int cancelbutton = -1;
|
|
int backbutton = -1;
|
|
int fwdbutton = -1;
|
|
int bcount = 0;
|
|
int rc = 0;
|
|
int i = 0;
|
|
const char *buttons[4] = { NULL, NULL, NULL, NULL };
|
|
const char *locButtons[4] = { NULL, NULL, NULL, NULL };
|
|
assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(locButtons));
|
|
|
|
cancelbutton = bcount++;
|
|
buttons[cancelbutton] = "cancel";
|
|
locButtons[cancelbutton] = xstrdup(_("Cancel"));
|
|
|
|
if (can_back)
|
|
{
|
|
backbutton = bcount++;
|
|
buttons[backbutton] = "back";
|
|
locButtons[backbutton] = xstrdup(_("Back"));
|
|
} // if
|
|
|
|
if (can_fwd)
|
|
{
|
|
fwdbutton = bcount++;
|
|
buttons[fwdbutton] = "next";
|
|
locButtons[fwdbutton] = xstrdup(_("Next"));
|
|
} // if
|
|
|
|
strAdd(&html, &len, &alloc,
|
|
"<form name='form_productkey' method='get'>"
|
|
"%s<br/>"
|
|
"<input type='text' name='productkey' value='%s'>"
|
|
"</form>", prompt, ((*buf) ? buf : ""));
|
|
|
|
free(prompt);
|
|
|
|
rc = doPromptPage(desc, html, true, "productkey",
|
|
buttons, locButtons, bcount);
|
|
|
|
free(html);
|
|
for (i = 0; i < STATICARRAYLEN(locButtons); i++)
|
|
free((void *) locButtons[i]);
|
|
|
|
if (rc == backbutton)
|
|
retval = -1;
|
|
else if (rc == cancelbutton)
|
|
retval = 0;
|
|
else
|
|
{
|
|
WebRequest *req = webRequest;
|
|
const char *keyval = NULL;
|
|
while (req != NULL)
|
|
{
|
|
const char *k = req->key;
|
|
const char *v = req->value;
|
|
if (strcmp(k, "productkey") == 0)
|
|
keyval = v;
|
|
|
|
req = req->next;
|
|
} // while
|
|
|
|
if (keyval == NULL)
|
|
retval = 0; // !!! FIXME: maybe loop with doPromptPage again.
|
|
else
|
|
{
|
|
snprintf(buf, buflen, "%s", keyval);
|
|
if (isValidProductKey(fmt, buf))
|
|
retval = 1;
|
|
// !!! FIXME: must try again if invalid key.
|
|
} // else
|
|
} // else
|
|
|
|
return retval;
|
|
} // MojoGui_www_productkey
|
|
|
|
|
|
static boolean MojoGui_www_insertmedia(const char *medianame)
|
|
{
|
|
char *htmltext = NULL;
|
|
char *text = NULL;
|
|
size_t len = 0, alloc = 0;
|
|
int i, rc;
|
|
|
|
const char *buttons[] = { "cancel", "ok" };
|
|
const char *locButtons[] = { htmlescape(_("Cancel")), htmlescape(_("OK")) };
|
|
|
|
char *title = xstrdup(_("Media change"));
|
|
char *fmt = xstrdup(_("Please insert '%0'"));
|
|
char *msg = format(fmt, medianame);
|
|
strAdd(&text, &len, &alloc, msg);
|
|
free(msg);
|
|
free(fmt);
|
|
|
|
htmltext = htmlescape(text);
|
|
free(text);
|
|
|
|
assert(STATICARRAYLEN(buttons) == STATICARRAYLEN(locButtons));
|
|
|
|
rc = doPromptPage(title, htmltext, true, "insertmedia", buttons,
|
|
locButtons, STATICARRAYLEN(buttons));
|
|
|
|
free(title);
|
|
free(htmltext);
|
|
for (i = 0; i < STATICARRAYLEN(locButtons); i++)
|
|
free((void *) locButtons[i]);
|
|
|
|
return (rc == 1);
|
|
} // MojoGui_www_insertmedia
|
|
|
|
|
|
static void MojoGui_www_progressitem(void)
|
|
{
|
|
// no-op in this UI target.
|
|
} // MojoGui_www_progressitem
|
|
|
|
|
|
static boolean MojoGui_www_progress(const char *type, const char *component,
|
|
int percent, const char *item,
|
|
boolean can_cancel)
|
|
{
|
|
return true;
|
|
} // MojoGui_www_progress
|
|
|
|
|
|
static void MojoGui_www_final(const char *msg)
|
|
{
|
|
MojoGui_www_msgbox(_("Finish"), msg);
|
|
} // MojoGui_www_final
|
|
|
|
// end of gui_www.c ...
|
|
|