diff options
Diffstat (limited to 'tests/ce-server.c')
-rw-r--r-- | tests/ce-server.c | 299 |
1 files changed, 292 insertions, 7 deletions
diff --git a/tests/ce-server.c b/tests/ce-server.c index 1f4a46d..06f67af 100644 --- a/tests/ce-server.c +++ b/tests/ce-server.c @@ -38,6 +38,11 @@ #endif #include <errno.h> +#ifdef HAVE_W32CE_SYSTEM +#ifndef FILE_ATTRIBUTE_ROMSTATICREF +#define FILE_ATTRIBUTE_ROMSTATICREF FILE_ATTRIBUTE_OFFLINE +#endif +#endif #include "../src/assuan.h" @@ -49,8 +54,25 @@ static short server_port = 15898; /* Flag set to indicate a shutdown. */ static int shutdown_pending; +/* The local state of a connection. */ +struct state_s +{ + char *cwd; /* The current working directory - access using get_cwd(). */ +}; +typedef struct state_s *state_t; + +static void +release_state (state_t state) +{ + if (!state) + return; + xfree (state->cwd); + xfree (state); +} + + /* Helper to print a message while leaving a command. */ static gpg_error_t leave_cmd (assuan_context_t ctx, gpg_error_t err) @@ -70,6 +92,114 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err) } +#ifdef HAVE_W32CE_SYSTEM +static char * +wchar_to_utf8 (const wchar_t *string) +{ + int n; + size_t length = wcslen (string); + char *result; + + n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL); + if (n < 0 || (n+1) <= 0) + log_fatal ("WideCharToMultiByte failed\n"); + + result = xmalloc (n+1); + n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL); + if (n < 0) + log_fatal ("WideCharToMultiByte failed\n"); + + result[n] = 0; + return result; +} + +static wchar_t * +utf8_to_wchar (const char *string) +{ + int n; + size_t length = strlen (string); + wchar_t *result; + size_t nbytes; + + n = MultiByteToWideChar (CP_UTF8, 0, string, length, NULL, 0); + if (n < 0 || (n+1) <= 0) + log_fatal ("MultiByteToWideChar failed\n"); + + nbytes = (size_t)(n+1) * sizeof(*result); + if (nbytes / sizeof(*result) != (n+1)) + log_fatal ("utf8_to_wchar: integer overflow\n"); + result = xmalloc (nbytes); + n = MultiByteToWideChar (CP_UTF8, 0, string, length, result, n); + if (n < 0) + log_fatal ("MultiByteToWideChar failed\n"); + result[n] = 0; + + return result; +} +#endif /*HAVE_W32CE_SYSTEM*/ + +#ifndef HAVE_W32CE_SYSTEM +static char * +gnu_getcwd (void) +{ + size_t size = 100; + + while (1) + { + char *buffer = xmalloc (size); + if (getcwd (buffer, size) == buffer) + return buffer; + xfree (buffer); + if (errno != ERANGE) + return 0; + size *= 2; + } +} +#endif /*!HAVE_W32CE_SYSTEM*/ + + +/* Return the current working directory. The returned string is valid + as long as STATE->cwd is not changed. */ +static const char * +get_cwd (state_t state) +{ + if (!state->cwd) + { + /* No working directory yet. On WindowsCE make it the module + directory of this process. */ + char *p; +#ifdef HAVE_W32CE_SYSTEM + wchar_t buf[MAX_PATH+1]; + size_t n; + + n = GetModuleFileName (NULL, buf, MAX_PATH); + if (!n) + state->cwd = xstrdup ("/"); + else + { + buf[n] = 0; + state->cwd = wchar_to_utf8 (buf); + p = strrchr (state->cwd, '\\'); + if (p) + *p = 0; + } +#else + state->cwd = gnu_getcwd (); +#endif +#ifdef HAVE_W32_SYSTEM + for (p=state->cwd; *p; p++) + if (*p == '\\') + *p = '/'; +#endif /*HAVE_W32_SYSTEM*/ + } + + return state->cwd; +} + + + + + @@ -88,13 +218,155 @@ cmd_echo (assuan_context_t ctx, char *line) } +static const char hlp_pwd[] = + "PWD\n" + "\n" + "Print the curent working directory of this session.\n"; +static gpg_error_t +cmd_pwd (assuan_context_t ctx, char *line) +{ + state_t state = assuan_get_pointer (ctx); + gpg_error_t err; + const char *string; + + string = get_cwd (state); + err = assuan_send_data (ctx, string, strlen (string)); -static const char hlp_killserver[] = - "KILLSERVER\n" + return leave_cmd (ctx, err); +} + + +static const char hlp_cd[] = + "CD [dir]\n" "\n" - "Kill the server process.\n"; + "Change the curretn directory of the session.\n"; static gpg_error_t -cmd_killserver (assuan_context_t ctx, char *line) +cmd_cd (assuan_context_t ctx, char *line) +{ + state_t state = assuan_get_pointer (ctx); + gpg_error_t err = 0; + char *newdir, *p; + + for (p=line; *p; p++) + if (*p == '\\') + *p = '/'; + + if (!*line) + { + xfree (state->cwd); + state->cwd = NULL; + get_cwd (state); + } + else + { + if (*line == '/') + newdir = xstrdup (line); + else + newdir = xstrconcat (get_cwd (state), "/", line, NULL); + + while (strlen(newdir) > 1 && line[strlen(newdir)-1] == '/') + line[strlen(newdir)-1] = 0; + xfree (state->cwd); + state->cwd = newdir; + } + + return leave_cmd (ctx, err); +} + + + + + +#ifdef HAVE_W32CE_SYSTEM +static const char hlp_ls[] = + "LS [<pattern>]\n" + "\n" + "List the files described by PATTERN.\n"; +static gpg_error_t +cmd_ls (assuan_context_t ctx, char *line) +{ + state_t state = assuan_get_pointer (ctx); + gpg_error_t err; + WIN32_FIND_DATA fi; + char buf[500]; + HANDLE hd; + char *p, *fname; + wchar_t *wfname; + + if (!*line) + fname = xstrconcat (get_cwd (state), "/*", NULL); + else if (*line == '/' || *line == '\\') + fname = xstrdup (line); + else + fname = xstrconcat (get_cwd (state), "/", line, NULL); + for (p=fname; *p; p++) + if (*p == '/') + *p = '\\'; + assuan_write_status (ctx, "PATTERN", fname); + wfname = utf8_to_wchar (fname); + xfree (fname); + hd = FindFirstFile (wfname, &fi); + free (wfname); + if (hd == INVALID_HANDLE_VALUE) + { + log_info ("FindFirstFile returned %d\n", GetLastError ()); + err = gpg_error_from_syserror (); /* Works for W32CE. */ + goto leave; + } + + do + { + DWORD attr = fi.dwFileAttributes; + + fname = wchar_to_utf8 (fi.cFileName); + snprintf (buf, sizeof buf, + "%c%c%c%c%c%c%c%c%c%c%c%c%c %7lu%c %s\n", + (attr & FILE_ATTRIBUTE_DIRECTORY) + ? ((attr & FILE_ATTRIBUTE_DEVICE)? 'c':'d'):'-', + (attr & FILE_ATTRIBUTE_READONLY)? 'r':'-', + (attr & FILE_ATTRIBUTE_HIDDEN)? 'h':'-', + (attr & FILE_ATTRIBUTE_SYSTEM)? 's':'-', + (attr & FILE_ATTRIBUTE_ARCHIVE)? 'a':'-', + (attr & FILE_ATTRIBUTE_COMPRESSED)? 'c':'-', + (attr & FILE_ATTRIBUTE_ENCRYPTED)? 'e':'-', + (attr & FILE_ATTRIBUTE_INROM)? 'R':'-', + (attr & FILE_ATTRIBUTE_REPARSE_POINT)? 'P':'-', + (attr & FILE_ATTRIBUTE_ROMMODULE)? 'M':'-', + (attr & FILE_ATTRIBUTE_ROMSTATICREF)? 'R':'-', + (attr & FILE_ATTRIBUTE_SPARSE_FILE)? 'S':'-', + (attr & FILE_ATTRIBUTE_TEMPORARY)? 't':'-', + (unsigned long)fi.nFileSizeLow, + fi.nFileSizeHigh? 'X':' ', + fname); + free (fname); + err = assuan_send_data (ctx, buf, strlen (buf)); + if (!err) + err = assuan_send_data (ctx, NULL, 0); + } + while (!err && FindNextFile (hd, &fi)); + if (err) + ; + else if (GetLastError () == ERROR_NO_MORE_FILES) + err = 0; + else + { + log_info ("FindNextFile returned %d\n", GetLastError ()); + err = gpg_error_from_syserror (); + } + FindClose (hd); + + leave: + return leave_cmd (ctx, err); +} +#endif /*HAVE_W32CE_SYSTEM*/ + + +static const char hlp_shutdown[] = + "SHUTDOWN\n" + "\n" + "Shutdown the server process after ending this connection\n"; +static gpg_error_t +cmd_shutdown (assuan_context_t ctx, char *line) { (void)ctx; (void)line; @@ -113,10 +385,15 @@ register_commands (assuan_context_t ctx) const char * const help; } table[] = { +#ifdef HAVE_W32CE_SYSTEM + { "LS", cmd_ls, hlp_ls }, +#endif + { "PWD", cmd_pwd, hlp_pwd }, + { "CD", cmd_cd, hlp_cd }, { "ECHO", cmd_echo, hlp_echo }, { "INPUT", NULL }, { "OUTPUT", NULL }, - { "KILLSERVER", cmd_killserver, hlp_killserver }, + { "SHUTDOWN", cmd_shutdown, hlp_shutdown }, { NULL, NULL } }; int i; @@ -143,6 +420,7 @@ server (void) int one = 1; struct sockaddr_in name; assuan_context_t ctx; + state_t state = NULL; err = assuan_new (&ctx); if (err) @@ -184,7 +462,12 @@ server (void) if (err) log_fatal ("register_commands failed: %s\n", gpg_strerror(err)); - assuan_set_log_stream (ctx, stderr); + if (debug) + assuan_set_log_stream (ctx, stderr); + + + state = xcalloc (1, sizeof state); + assuan_set_pointer (ctx, state); while (!shutdown_pending) { @@ -206,6 +489,7 @@ server (void) assuan_sock_close (server_fd); assuan_release (ctx); + release_state (state); } @@ -254,7 +538,8 @@ main (int argc, char **argv) } assuan_set_assuan_log_prefix (log_prefix); - assuan_set_assuan_log_stream (stderr); + if (debug) + assuan_set_assuan_log_stream (stderr); err = assuan_sock_init (); if (err) |