Beispiel #1
0
static switch_xml_t fetch_handler(const char *section, const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params, void *user_data) {
    switch_xml_t xml = NULL;
    switch_uuid_t uuid;
    switch_time_t now = 0;
    ei_xml_agent_t *agent = (ei_xml_agent_t *) user_data;
    ei_xml_client_t *client;
    fetch_handler_t *fetch_handler;
    xml_fetch_reply_t reply, *pending, *prev = NULL;

    now = switch_micro_time_now();

    if (!switch_test_flag(&globals, LFLAG_RUNNING)) {
        return xml;
    }

    /* read-lock the agent */
    switch_thread_rwlock_rdlock(agent->lock);

    /* serialize access to current, used to round-robin requests */
    /* TODO: check globals for round-robin boolean or loop all clients */
    switch_mutex_lock(agent->current_client_mutex);
    if (!agent->current_client) {
        client = agent->clients;
    } else {
        client = agent->current_client;
    }
    if (client) {
        agent->current_client = client->next;
    }
    switch_mutex_unlock(agent->current_client_mutex);

    /* no client, no work required */
    if (!client || !client->fetch_handlers) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "No %s XML erlang handler currently available\n"
                          ,section);
        switch_thread_rwlock_unlock(agent->lock);
        return xml;
    }

    /* prepare the reply collector */
    switch_uuid_get(&uuid);
    switch_uuid_format(reply.uuid_str, &uuid);
    reply.next = NULL;
    reply.xml_str = NULL;

    /* add our reply placeholder to the replies list */
    switch_mutex_lock(agent->replies_mutex);
    if (!agent->replies) {
        agent->replies = &reply;
    } else {
        reply.next = agent->replies;
        agent->replies = &reply;
    }
    switch_mutex_unlock(agent->replies_mutex);

    fetch_handler = client->fetch_handlers;
    while (fetch_handler != NULL) {
        ei_send_msg_t *send_msg;

        switch_malloc(send_msg, sizeof(*send_msg));
        memcpy(&send_msg->pid, &fetch_handler->pid, sizeof(erlang_pid));

        ei_x_new_with_version(&send_msg->buf);

        ei_x_encode_tuple_header(&send_msg->buf, 7);
        ei_x_encode_atom(&send_msg->buf, "fetch");
        ei_x_encode_atom(&send_msg->buf, section);
        _ei_x_encode_string(&send_msg->buf, tag_name ? tag_name : "undefined");
        _ei_x_encode_string(&send_msg->buf, key_name ? key_name : "undefined");
        _ei_x_encode_string(&send_msg->buf, key_value ? key_value : "undefined");
        _ei_x_encode_string(&send_msg->buf, reply.uuid_str);

        if (params) {
            ei_encode_switch_event_headers(&send_msg->buf, params);
        } else {
            ei_x_encode_empty_list(&send_msg->buf);
        }

        if (switch_queue_trypush(client->ei_node->send_msgs, send_msg) != SWITCH_STATUS_SUCCESS) {
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send %s XML request to %s <%d.%d.%d>\n"
                              ,section
                              ,fetch_handler->pid.node
                              ,fetch_handler->pid.creation
                              ,fetch_handler->pid.num
                              ,fetch_handler->pid.serial);
            ei_x_free(&send_msg->buf);
            switch_safe_free(send_msg);
        } else {
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending %s XML request (%s) to %s <%d.%d.%d>\n"
                              ,section
                              ,reply.uuid_str
                              ,fetch_handler->pid.node
                              ,fetch_handler->pid.creation
                              ,fetch_handler->pid.num
                              ,fetch_handler->pid.serial);
        }

        fetch_handler = fetch_handler->next;
    }

    /* wait for a reply (if there isnt already one...amazingly improbable but lets not take shortcuts */
    switch_mutex_lock(agent->replies_mutex);

    switch_thread_rwlock_unlock(agent->lock);

    if (!reply.xml_str) {
        switch_time_t timeout;

        timeout = switch_micro_time_now() + 3000000;
        while (switch_micro_time_now() < timeout) {
            /* unlock the replies list and go to sleep, calculate a three second timeout before we started the loop
             * plus 100ms to add a little hysteresis between the timeout and the while loop */
            switch_thread_cond_timedwait(agent->new_reply, agent->replies_mutex, (timeout - switch_micro_time_now() + 100000));

            /* if we woke up (and therefore have locked replies again) check if we got our reply
             * otherwise we either timed-out (the while condition will fail) or one of
             * our sibling processes got a reply and we should go back to sleep */
            if (reply.xml_str) {
                break;
            }
        }
    }

    /* find our reply placeholder in the linked list and remove it */
    pending = agent->replies;
    while (pending != NULL) {
        if (pending->uuid_str == reply.uuid_str) {
            break;
        }

        prev = pending;
        pending = pending->next;
    }

    if (pending) {
        if (!prev) {
            agent->replies = reply.next;
        } else {
            prev->next = reply.next;
        }
    }

    /* we are done with the replies link-list */
    switch_mutex_unlock(agent->replies_mutex);

    /* after all that did we get what we were after?! */
    if (reply.xml_str) {
        /* HELL YA WE DID */
        reply.xml_str = expand_vars(reply.xml_str);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received %s XML (%s) after %dms: %s\n"
                          ,section
                          ,reply.uuid_str
                          ,(unsigned int) (switch_micro_time_now() - now) / 1000
                          ,reply.xml_str);

        xml = switch_xml_parse_str_dynamic(reply.xml_str, SWITCH_FALSE);
    } else {
        /* facepalm */
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Request for %s XML (%s) timed-out after %dms\n"
                          ,section
                          ,reply.uuid_str
                          ,(unsigned int) (switch_micro_time_now() - now) / 1000);
    }

    return xml;
}
Beispiel #2
0
static void __execute_function(
	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
	FUNC_FLAGS_TYPE exec_flags, char *args[], Bool has_ref_window_moved)
{
	static int func_depth = 0;
	cond_rc_t *func_rc = NULL;
	cond_rc_t dummy_rc;
	Window w;
	int j;
	char *function;
	char *taction;
	char *trash;
	char *trash2;
	char *expaction = NULL;
	char *arguments[11];
	const func_t *bif;
	Bool set_silent;
	Bool must_free_string = False;
	Bool must_free_function = False;
	Bool do_keep_rc = False;
	/* needed to be able to avoid resize to use moved windows for base */
	extern Window PressedW;
	Window dummy_w;

	if (!action)
	{
		return;
	}
	/* ignore whitespace at the beginning of all config lines */
	action = SkipSpaces(action, NULL, 0);
	if (!action || action[0] == 0)
	{
		/* impossibly short command */
		return;
	}
	if (action[0] == '#')
	{
		/* a comment */
		return;
	}

	func_depth++;
	if (func_depth > MAX_FUNCTION_DEPTH)
	{
		fvwm_msg(
			ERR, "__execute_function",
			"Function '%s' called with a depth of %i, "
			"stopping function execution!",
			action, func_depth);
		func_depth--;
		return;
	}
	if (args)
	{
		for (j = 0; j < 11; j++)
		{
			arguments[j] = args[j];
		}
	}
	else
	{
		for (j = 0; j < 11; j++)
		{
			arguments[j] = NULL;
		}
	}

	if (exc->w.fw == NULL || IS_EWMH_DESKTOP(FW_W(exc->w.fw)))
	{
		if (exec_flags & FUNC_IS_UNMANAGED)
		{
			w = exc->w.w;
		}
		else
		{
			w = Scr.Root;
		}
	}
	else
	{
		FvwmWindow *tw;

		w = GetSubwindowFromEvent(dpy, exc->x.elast);
		if (w == None)
		{
			w = exc->x.elast->xany.window;
		}
		tw = NULL;
		if (w != None)
		{
			if (XFindContext(
				 dpy, w, FvwmContext, (caddr_t *)&tw) ==
			    XCNOENT)
			{
				tw = NULL;
			}
		}
		if (w == None || tw != exc->w.fw)
		{
			w = FW_W(exc->w.fw);
		}
	}

	set_silent = False;
	if (action[0] == '-')
	{
		exec_flags |= FUNC_DONT_EXPAND_COMMAND;
		action++;
	}

	taction = action;
	/* parse prefixes */
	trash = PeekToken(taction, &trash2);
	while (trash)
	{
		if (StrEquals(trash, PRE_SILENT))
		{
			if (Scr.flags.are_functions_silent == 0)
			{
				set_silent = 1;
				Scr.flags.are_functions_silent = 1;
			}
			taction = trash2;
			trash = PeekToken(taction, &trash2);
		}
		else if (StrEquals(trash, PRE_KEEPRC))
		{
			do_keep_rc = True;
			taction = trash2;
			trash = PeekToken(taction, &trash2);
		}
		else
		{
			break;
		}
	}
	if (taction == NULL)
	{
		if (set_silent)
		{
			Scr.flags.are_functions_silent = 0;
		}
		func_depth--;
		return;
	}
	if (cond_rc == NULL || do_keep_rc == True)
	{
		condrc_init(&dummy_rc);
		func_rc = &dummy_rc;
	}
	else
	{
		func_rc = cond_rc;
	}

	GetNextToken(taction, &function);
	if (function)
	{
		char *tmp = function;
		function = expand_vars(
			function, arguments, False, False, func_rc, exc);
		free(tmp);
	}
	if (function && function[0] != '*')
	{
#if 1
		/* DV: with this piece of code it is impossible to have a
		 * complex function with embedded whitespace that begins with a
		 * builtin function name, e.g. a function "echo hello". */
		/* DV: ... and without it some of the complex functions will
		 * fail */
		char *tmp = function;

		while (*tmp && !isspace(*tmp))
		{
			tmp++;
		}
		*tmp = 0;
#endif
		bif = find_builtin_function(function);
		must_free_function = True;
	}
	else
	{
		bif = NULL;
		if (function)
		{
			free(function);
		}
		function = "";
	}

	if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor &&
	    (!bif || !(bif->flags & FUNC_DECOR)))
	{
		fvwm_msg(
			ERR, "__execute_function",
			"Command can not be added to a decor; executing"
			" command now: '%s'", action);
	}

	if (!(exec_flags & FUNC_DONT_EXPAND_COMMAND))
	{
		expaction = expand_vars(
			taction, arguments, (bif) ?
			!!(bif->flags & FUNC_ADD_TO) :
			False, (taction[0] == '*'), func_rc, exc);
		if (func_depth <= 1)
		{
			must_free_string = set_repeat_data(
				expaction, REPEAT_COMMAND, bif);
		}
		else
		{
			must_free_string = True;
		}
	}
	else
	{
		expaction = taction;
	}

#ifdef FVWM_COMMAND_LOG
	fvwm_msg(INFO, "LOG", "%c: %s", (char)exc->type, expaction);
#endif

	/* Note: the module config command, "*" can not be handled by the
	 * regular command table because there is no required white space after
	 * the asterisk. */
	if (expaction[0] == '*')
	{
		if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
		{
			fvwm_msg(
				WARN, "__execute_function",
				"Command can not be added to a decor;"
				" executing command now: '%s'", expaction);
		}

		/* process a module config command */
		ModuleConfig(expaction);
	}
	else
	{
		const exec_context_t *exc2;
		exec_context_changes_t ecc;
		exec_context_change_mask_t mask;

		mask = (w != exc->w.w) ? ECC_W : 0;
		ecc.w.fw = exc->w.fw;
		ecc.w.w = w;
		ecc.w.wcontext = exc->w.wcontext;
		if (bif && bif->func_t != F_FUNCTION)
		{
			char *runaction;
			Bool rc = False;

			runaction = SkipNTokens(expaction, 1);
			if ((bif->flags & FUNC_NEEDS_WINDOW) &&
			    !(exec_flags & FUNC_DONT_DEFER))
			{
				rc = DeferExecution(
					&ecc, &mask, bif->cursor,
					exc->x.elast->type,
					(bif->flags & FUNC_ALLOW_UNMANAGED));
			}
			else if ((bif->flags & FUNC_NEEDS_WINDOW) &&
				 !__context_has_window(
					 exc,
					 bif->flags & FUNC_ALLOW_UNMANAGED))
			{
				/* no context window and not allowed to defer,
				 * skip command */
				rc = True;
			}
			if (rc == False)
			{
				exc2 = exc_clone_context(exc, &ecc, mask);
				if (has_ref_window_moved &&
				    (bif->func_t == F_ANIMATED_MOVE ||
				     bif->func_t == F_MOVE ||
				     bif->func_t == F_RESIZE ||
				     bif->func_t == F_RESIZEMOVE ||
				     bif->func_t == F_RESIZE_MAXIMIZE ||
				     bif->func_t == F_RESIZEMOVE_MAXIMIZE))
				{
					dummy_w = PressedW;
					PressedW = None;
					bif->action(func_rc, exc2, runaction);
					PressedW = dummy_w;
				}
				else
				{
					bif->action(func_rc, exc2, runaction);
				}
				exc_destroy_context(exc2);
			}
		}
		else
		{
			Bool desperate = 1;
			char *runaction;

			if (bif)
			{
				/* strip "function" command */
				runaction = SkipNTokens(expaction, 1);
			}
			else
			{
				runaction = expaction;
			}
			exc2 = exc_clone_context(exc, &ecc, mask);
			execute_complex_function(
				func_rc, exc2, runaction, &desperate,
				has_ref_window_moved);
			if (!bif && desperate)
			{
				if (executeModuleDesperate(
					    func_rc, exc, runaction) == NULL &&
				    *function != 0 && !set_silent)
				{
					fvwm_msg(
						ERR, "__execute_function",
						"No such command '%s'",
						function);
				}
			}
			exc_destroy_context(exc2);
		}
	}

	if (set_silent)
	{
		Scr.flags.are_functions_silent = 0;
	}
	if (cond_rc != NULL)
	{
		cond_rc->break_levels = func_rc->break_levels;
	}
	if (must_free_string)
	{
		free(expaction);
	}
	if (must_free_function)
	{
		free(function);
	}
	func_depth--;

	return;
}
Beispiel #3
0
static int parse_directive(ssi_buffer* ssib, char* str, int len) {
  assert(!str[len]); // zero-terminated
  char* p=str;
  char* pe=str+len;
  char* attr_name[SSI_MAX_ATTRS];
  char* attr_value[SSI_MAX_ATTRS];
  int num_attr=0;
  while ((unsigned char)*p<=SPACE && p<pe) p++;
  if (p>=pe) return -1;
  char* cmd=p;
  while ((unsigned char)*p>SPACE) p++;
  *p++='\0';
  while (num_attr<SSI_MAX_ATTRS) {
    attr_name[num_attr]=p;
    p=strchr(p, '=');
    if (!p) break;
    *p++='\0';
    attr_name[num_attr]=nxweb_trunc_space(attr_name[num_attr]);
    while ((unsigned char)*p<=SPACE && p<pe) p++;
    if (p>=pe) return -1;
    char q=*p++;
    if (q!='\"' && q!='\'') return -1;
    attr_value[num_attr]=p;
    p=strchr(p, q);
    if (!p) return -1;
    *p++='\0';
    num_attr++;
  }

  if (!strcmp(cmd, "include")) {
    int i;
    for (i=0; i<num_attr; i++) {
      if (!strcmp(attr_name[i], "virtual")) {
        const char* expanded=expand_vars(ssib, attr_value[i]);
        if (!expanded) {
          nxweb_log_warning("ssi variables expansion failure: %s @ %s", attr_value[i], ssib->req->uri);
          return -1;
        }
        // nxweb_log_error("ssi variables expanded: %s -> %s", attr_value[i], expanded);
        nxweb_composite_stream_append_subrequest(ssib->cs, ssib->cs->req->host, expanded);
        return 0;
      }
    }
  }
  else if (!strcmp(cmd, "set")) {
    int i;
    const char* var_name=0;
    const char* var_value=0;
    nx_simple_map_entry* param;
    for (i=0; i<num_attr; i++) {
      if (!strcmp(attr_name[i], "var")) {
        var_name=attr_value[i];
      }
      else if (!strcmp(attr_name[i], "value")) {
        var_value=expand_vars(ssib, attr_value[i]);
        if (!var_value) {
          nxweb_log_warning("ssi set variable expansion failure: %s @ %s", attr_value[i], ssib->req->uri);
          return -1;
        }
        // nxweb_log_error("ssi variables expanded: %s -> %s", attr_value[i], var_value);
      }
    }
    if (var_name && var_value) {
      param=nx_simple_map_find(ssib->var_map, var_name);
      if (!param) {
        param=nxb_calloc_obj(ssib->nxb, sizeof(nx_simple_map_entry));
        ssib->var_map=nx_simple_map_add(ssib->var_map, param);
        param->name=var_name;
      }
      param->value=var_value;
      return 0;
    }
  }
  else if (!strcmp(cmd, "echo")) {
    int i;
    for (i=0; i<num_attr; i++) {
      if (!strcmp(attr_name[i], "var")) {
        const char* var_name=attr_value[i];
        char expanded[SSI_MAX_EXPR_LEN];
        char* end=expand_var(ssib, var_name, strlen(var_name), expanded, SSI_MAX_EXPR_LEN);
        if (!end) {
          // nxweb_log_warning("ssi echo variable expansion failure: %s @ %s", var_name, ssib->req->uri);
          return -1;
        }
        int len=end-expanded;
        char* buf=nxb_copy_obj(ssib->nxb, expanded, len);
        nxweb_composite_stream_append_bytes(ssib->cs, buf, len);
        return 0;
      }
    }
  }
  return -1;
}
Beispiel #4
0
/* evaluate a simple command (3.9.1)
 * 
 * this function doesn't put stuff in background, it always wait()s, so
 * it only needs to fork() real programs
 * ----------------------------------------------------------------------- */
int eval_simple_command(struct eval *e, struct ncmd *ncmd) {
  union node *nptr;
  int argc;
  char **argv;
  int status;
  union node *args = NULL;
  union node *assigns = NULL;
  union command cmd = { NULL };
  enum hash_id id = H_BUILTIN;
  struct vartab vars;
/*  struct fdstack io;*/
  union node *r;
  union node *redir = ncmd->rdir;

  /* expand arguments,
     if there are arguments we start a hashed search for the command */
  if(expand_args(ncmd->args, &args, 0)) {
    stralloc_nul(&args->narg.stra);
    cmd = exec_hash(args->narg.stra.s, &id);
  }

  /* expand and set the variables,
     mark them for export if we're gonna execute a command */
  if(expand_vars(ncmd->vars, &assigns)) {
    /* if we don't exit after the command, have a command and not a 
       special builtin the variable changes should be temporary */
    if(!(e->flags & E_EXIT) && cmd.ptr && id != H_SBUILTIN)
      vartab_push(&vars);
    
    for(nptr = assigns; nptr; nptr = nptr->list.next)
      var_setsa(&nptr->narg.stra, (cmd.ptr ? V_EXPORT : V_DEFAULT));

    tree_free(assigns);
  }
  
  /* do redirections if present */
/*  if(redir && id != H_SBUILTIN && id != H_EXEC)
    fdstack_push(&io);*/
    
  if(redir/* && id != H_PROGRAM*/) {
    for(r = redir; r; r = r->list.next) {
      struct fd *fd = NULL;
      
      /* if its the exec special builtin the new fd needs to be persistent */
      if(id != H_EXEC) fd_alloca(fd);
      
      /* return if a redirection failed */
      if(redir_eval(&r->nredir, fd, (id == H_EXEC ? R_NOW : 0))) {
        status = 1;
        goto end;
      }
      
      /* check if we need to initialize fd buffers for the new redirection */
      if(fd_needbuf(r->nredir.fd)) {
        /* if its not exec then set up buffers for 
           temporary redirections on the stack */
        if(id != H_EXEC)
          fd_setbuf(r->nredir.fd, alloca(FD_BUFSIZE), FD_BUFSIZE);
        else
          fd_allocbuf(r->nredir.fd, FD_BUFSIZE);
      }
    }
  }
  
  /* if there is no command we can return after 
     setting the vars and doing the redirections */
  if(args == NULL) {
    status = 0;
    goto end;
  }

  /* when the command wasn't found we abort */
  if(cmd.ptr == NULL) {
    sh_error(args->narg.stra.s);
    status = exec_error();
    goto end;
  }

  /* assemble argument list */
  argc = tree_count(args);
  
  argv = alloca((argc + 1) * sizeof(char *));
  expand_argv(args, argv);

  /* execute the command, this may or may not return, depending on E_EXIT */
  status = exec_command(id, cmd, argc, argv, (e->flags & E_EXIT), redir);

end:

  /* restore variable stack */
  if(varstack == &vars)
    vartab_pop(&vars);

  if(args)
    tree_free(args);
  
  /* undo redirections */
  if(id != H_EXEC) {
    for(r = redir; r; r = r->list.next)
      fd_pop(r->nredir.fd);
  }
  
/*  if(fdstack == &io)
    fdstack_pop(&io);*/

  return status;
}
Beispiel #5
0
/* Runs a handler process specified by full command line <data> (with arguments).
 * Before running:
 * Replaces environment variables.
 * Replaces special MimeRun variables (see above) with the detected values taken from <mres>.
 * Replaces %* and %N with the appropriate bits of <lpfile> and <einfo>->lpParameters.
 * If <executable> is TRUE, waits until the handler process terminates, otherwise returns
 * (almost) immediately.
 */
int run_handler (wchar_t *logfile, wchar_t *data, MimeResults *mres, LPSHELLEXECUTEINFOW einfo, wchar_t *lpfile, wchar_t *lpdir, int executable, int fix_redir)
{
  BOOL ret = 0;
  PVOID redir;
  HMODULE kernel32 = NULL;
  Wow64DisableWow64FsRedirectionFunction disablewow64 = NULL;
  Wow64RevertWow64FsRedirectionFunction revertwow64 = NULL;
  DWORD err;
  int i;
  int depth = 0;
  size_t dupdatalen;
  wchar_t *exp_data = NULL;
  wchar_t *dupdata = NULL;
  wchar_t *dupparams = NULL;
  wchar_t **old_argv = NULL, **newargv = NULL;
  STARTUPINFOW si;
  PROCESS_INFORMATION pi;
  DWORD applelen, typelen, enclen, namelen;
  wchar_t *store_apple = NULL, *store_type = NULL, *store_enc = NULL, *store_name = NULL;

  logtofilew (logfile, L">run_handler\n");

  if (einfo->lpParameters != NULL)
  {
    i = wcslen (einfo->lpParameters) + 1 + wcslen (lpfile);
    logtofilew (logfile, L"Fake commandline length is %d + 1 + %d == %d\n", wcslen (einfo->lpParameters), wcslen (lpfile), i);
    dupparams = (wchar_t *) malloc (sizeof (wchar_t *) * (i + 1));
    if (dupparams == NULL)
    {
      logtofilew (logfile, L"Failed to allocate %d bytes\n", sizeof (wchar_t *) * (i + 1));
      return 1;
    }
    dupparams[0] = L'\0';
    wcscat (dupparams, lpfile);
    wcscat (dupparams, L" ");
    wcscat (dupparams, einfo->lpParameters);
    logtofilew (logfile, L"Fake commandline is %s\n", dupparams);
    if (make_argv (dupparams, &i, NULL) == 0 && i >= 1)
    {
      old_argv = (wchar_t **) malloc (sizeof (wchar_t *) * (i + 1));
      make_argv (dupparams, NULL, old_argv);
      old_argv[i] = NULL;
      logtofilew (logfile, L"Old arguments:\n");
      for (i = 0; old_argv[i] != NULL; i++)
        logtofilew (logfile, L"%2d: %s\n", i, old_argv[i]);
      logtofilew (logfile, L"\n");
    }
    else
    {
      logtofilew (logfile, L"First call to make_argv() have failed or argc <= 0\n");
      free (dupparams);
      return 2;
    }
  }
  else
  {
    old_argv = (wchar_t **) malloc (sizeof (wchar_t *) * 2);
    old_argv[0] = lpfile;
    old_argv[1] = NULL;
    logtofilew (logfile, L"Old arguments:\n");
    for (i = 0; old_argv[i] != NULL; i++)
      logtofilew (logfile, L"%2d: %s\n", i, old_argv[i]);
    logtofilew (logfile, L"\n");
  }

  store_name = store_var (NAME_VARW, &namelen);
  store_type = store_var (TYPE_VARW, &typelen);
  store_enc = store_var (ENC_VARW, &enclen);
  store_apple = store_var (APPLE_VARW, &applelen);

  logtofilew (logfile, L"Backed up variables: {%s}, {%s}, {%s}, {%s}\n", store_name, store_type, store_enc, store_apple);

  SetEnvironmentVariableW (NAME_VARW, mres->wname == NULL ? L"" : mres->wname);
  SetEnvironmentVariableW (TYPE_VARW, mres->wtype == NULL ? L"" : mres->wtype);
  SetEnvironmentVariableW (ENC_VARW, mres->wenc == NULL ? L"" : mres->wenc);
  SetEnvironmentVariableW (APPLE_VARW, mres->wapple == NULL ? L"" : mres->wapple);
  
  exp_data = expand_vars (data, old_argv);

  logtofilew (logfile, L"Commandline with expanded variables: %s\n", exp_data);
  if (dupparams != NULL)
    free (dupparams);
  if (old_argv != NULL)
    free (old_argv);

  SetEnvironmentVariableW (NAME_VARW, store_name);
  SetEnvironmentVariableW (TYPE_VARW, store_type);
  SetEnvironmentVariableW (ENC_VARW, store_enc);
  SetEnvironmentVariableW (APPLE_VARW, store_apple);

  if (store_apple != NULL)
    free (store_apple);
  if (store_type != NULL)
    free (store_type);
  if (store_enc != NULL)
    free (store_enc);
  if (store_name != NULL)
    free (store_name);

  dupdata = (wchar_t *) wcsdup (exp_data);
  if (make_argv (dupdata, &i, NULL) == 0 && i >= 1)
  {
    newargv = (wchar_t **) malloc (sizeof (wchar_t *) * (i + 1));
    make_argv (dupdata, NULL, newargv);
    newargv[i] = NULL;
  }
  else
  {
    logtofilew (logfile, L"First call to make_argv() have failed or argc <= 0\n");
    free (dupdata);
    return 3;
  }

  memset (&si, 0, sizeof (si));
  si.cb = sizeof (si);
  if (einfo->nShow != SW_SHOWDEFAULT)
  {
    si.dwFlags |= STARTF_USESHOWWINDOW;
    si.wShowWindow = einfo->nShow;
    logtofilew (logfile, L"Using nShow == %d\n", si.wShowWindow);
  }


  if (einfo->fMask & SEE_MASK_NO_CONSOLE)
  {
    logtofilew (logfile, L"We will create new console and will not inherit in/out/err handles\n");
  }
  else
  {
    logtofilew (logfile, L"We will not create new console, child process will inherit in/out/err handles\n");
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
    si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
    si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
  }

  if (fix_redir && iam32on64 ())
  {
    kernel32 = LoadLibraryW (L"kernel32.dll");
    if (kernel32 != NULL)
    {
      disablewow64 = (Wow64DisableWow64FsRedirectionFunction) GetProcAddress (kernel32, "Wow64DisableWow64FsRedirection");
      revertwow64 = (Wow64RevertWow64FsRedirectionFunction) GetProcAddress (kernel32, "Wow64RevertWow64FsRedirection");
      if (disablewow64 == NULL || revertwow64 == NULL)
        fix_redir = 0;
      else
        fix_redir = disablewow64 (&redir);
    }
    else
      fix_redir = 0;
  }
  else
    fix_redir = 0;

  ret = CreateProcessW (newargv[0], exp_data, NULL, NULL, TRUE, einfo->fMask & SEE_MASK_NO_CONSOLE ? CREATE_NEW_CONSOLE : 0, NULL, lpdir, &si, &pi);
  err = GetLastError();
  if (fix_redir != 0)
    revertwow64 (redir);
  if (kernel32 != NULL)
    FreeLibrary (kernel32);

  if (ret != 0)
  {
    logtofilew (logfile, L"CreateProcessW() succeeded\n");
    ret = 0;
    if (executable)
    {
      logtofilew (logfile, L"Waiting until executable process terminates...\n");
      WaitForSingleObject (pi.hProcess, INFINITE);
      logtofilew (logfile, L"Finished waiting until executable process terminates\n");
    }
    else
    {
      if (einfo->fMask & SEE_MASK_NOCLOSEPROCESS)
      {
        einfo->hProcess = pi.hProcess;
        logtofilew (logfile, L"Will return process handle %08X\n", pi.hProcess);
      }
      if (einfo->fMask & SEE_MASK_WAITFORINPUTIDLE)
      {
        logtofilew (logfile, L"Waiting until non-executable process' input idles...\n");
        WaitForInputIdle (pi.hProcess, 60*1000);
        logtofilew (logfile, L"Finished waiting until non-executable process' input idles\n");
      }
    }
    einfo->hInstApp = (HINSTANCE) 33;
  }
  else
  {
    logtofilew (logfile, L"CreateProcessW() have failed with %d\n", err);
    switch (err)
    {
    case ERROR_FILE_NOT_FOUND:
      einfo->hInstApp = (HINSTANCE) SE_ERR_FNF;
      break;
    case ERROR_PATH_NOT_FOUND:
      einfo->hInstApp = (HINSTANCE) SE_ERR_PNF;
      break;
    case ERROR_ACCESS_DENIED:
      einfo->hInstApp = (HINSTANCE) SE_ERR_ACCESSDENIED;
      break;
    case ERROR_NOT_ENOUGH_MEMORY:
      einfo->hInstApp = (HINSTANCE) SE_ERR_OOM;
      break;
    default:
      einfo->hInstApp = (HINSTANCE) 33;
    }
    ret = 1;
  }
  logtofilew (logfile, L"hInstApp is set to %d\n", einfo->hInstApp);
  free (exp_data);
  if (dupdata != NULL)
    free (dupdata);
  if (newargv != NULL)
    free (newargv);
  logtofilew (logfile, L"<run_handler %d\n", ret);
  return ret;
}