static void tmate_client_exec_cmd(struct tmate_unpacker *uk) { struct cmd_q *cmd_q; struct cmd_list *cmdlist; char *cause; int client_id = unpack_int(uk); char *cmd_str = unpack_string(uk); if (cmd_string_parse(cmd_str, &cmdlist, NULL, 0, &cause) != 0) { tmate_failed_cmd(client_id, cause); free(cause); goto out; } /* error messages land in cfg_causes */ ARRAY_FREE(&cfg_causes); cmd_q = cmdq_new(NULL); cmdq_run(cmd_q, cmdlist); cmd_list_free(cmdlist); cmdq_free(cmd_q); if (!ARRAY_EMPTY(&cfg_causes)) { cause = ARRAY_ITEM(&cfg_causes, 0); tmate_failed_cmd(client_id, cause); free(cause); ARRAY_FREE(&cfg_causes); } out: free(cmd_str); }
// 调用函数 FAKE_API void fkrunps(fake * fk, const char * func) { FKLOG("fkrunps %p %s", fk, func); fk->rn.rundeps++; // 清空运行环境 fk->clearerr(); // 分配个 pool<processor>::node * n = 0; if (UNLIKE(POOL_EMPTY(fk->pp))) { POOL_GROW(fk->pp, pool<processor>::node, n); PROCESS_INI(n->t, fk); } POOL_POP(fk->pp, n); assert(ARRAY_EMPTY(n->t.m_pl.l)); assert(n->t.m_routine_num == 0); processor & pro = n->t; PROCESS_CLEAR(pro); variant funcv; V_SET_STRING(&funcv, func); routine * r = pro.start_routine(funcv, 0, 0); PUSH_CUR_PROCESSOR(n, fk->rn); // 单独执行,下次再跑run if (UNLIKE(fk->rn.stepmod)) { variant * ret = 0; bool err = false; PS_PUSH_AND_GET(fk->ps, ret); *ret = NILV; FKLOG("fkrunps %p %s yield", fk, func); CHECK_ERR(err); return; } pro.run(); POP_CUR_PROCESSOR(fk->rn); variant * ret = 0; bool err = false; PS_PUSH_AND_GET(fk->ps, ret); *ret = ROUTINE_GETRET(*r); CHECK_ERR(err); POOL_PUSH(fk->pp, n); fk->rn.rundeps--; FKLOG("fkrunps %p %s OK", fk, func); }
int include_finish(void) { if (ARRAY_EMPTY(&parse_filestack)) return (1); log_debug2("finished file %s", parse_file->path); xfree(parse_file); parse_file = ARRAY_LAST(&parse_filestack); ARRAY_TRUNC(&parse_filestack, 1); return (0); }
/* Initial state. */ int fetch_mbox_state_init(struct account *a, struct fetch_ctx *fctx) { struct fetch_mbox_data *data = a->data; if (fetch_mbox_make(a) != 0) return (FETCH_ERROR); if (ARRAY_EMPTY(&data->fmboxes)) { log_warnx("%s: no mboxes found", a->name); return (-1); } data->index = 0; TAILQ_INIT(&data->kept); fctx->state = fetch_mbox_state_open; return (FETCH_AGAIN); }
void cfg_show_causes(struct session *s) { struct window_pane *wp; char *cause; u_int i; if (s == NULL || ARRAY_EMPTY(&cfg_causes)) return; wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); window_copy_add(wp, "%s", cause); free(cause); } ARRAY_FREE(&cfg_causes); }
/* * Sometimes mail has wrapped header lines, this undoubtedly looks neat but * makes them a pain to match using regexps. We build a list of the newlines * in all the wrapped headers in m->wrapped, and can then quickly unwrap them * for regexp matching and wrap them again for delivery. */ u_int fill_wrapped(struct mail *m) { char *ptr; size_t end, off; u_int n; if (!ARRAY_EMPTY(&m->wrapped)) fatalx("already wrapped"); ARRAY_INIT(&m->wrapped); m->wrapchar = '\0'; end = m->body; ptr = m->data; n = 0; for (;;) { ptr = memchr(ptr, '\n', m->size - (ptr - m->data)); if (ptr == NULL) break; ptr++; off = ptr - m->data; if (off >= end) break; /* Check if the line starts with whitespace. */ if (!isblank((u_char) *ptr)) continue; /* Save the position. */ ARRAY_ADD(&m->wrapped, off - 1); n++; } return (n); }
int cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct causelist causes; char *cause; struct window_pane *wp; int retval; u_int i; ARRAY_INIT(&causes); retval = load_cfg(args->argv[0], ctx, &causes); if (ARRAY_EMPTY(&causes)) return (retval); if (retval == 1 && !RB_EMPTY(&sessions) && ctx->cmdclient != NULL) { wp = RB_MIN(sessions, &sessions)->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&causes); i++) { cause = ARRAY_ITEM(&causes, i); window_copy_add(wp, "%s", cause); xfree(cause); } } else { for (i = 0; i < ARRAY_LENGTH(&causes); i++) { cause = ARRAY_ITEM(&causes, i); ctx->print(ctx, "%s", cause); xfree(cause); } } ARRAY_FREE(&causes); return (retval); }
int cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct session *s, *old_s, *groupwith; struct window *w; struct window_pane *wp; struct environ env; struct termios tio, *tiop; struct passwd *pw; const char *newname, *target, *update, *cwd; char *overrides, *cmd, *cause; int detached, idx; u_int sx, sy, i; newname = args_get(args, 's'); if (newname != NULL && session_find(newname) != NULL) { ctx->error(ctx, "duplicate session: %s", newname); return (-1); } target = args_get(args, 't'); if (target != NULL) { groupwith = cmd_find_session(ctx, target); if (groupwith == NULL) return (-1); } else groupwith = NULL; /* * There are three cases: * * 1. If cmdclient is non-NULL, new-session has been called from the * command-line - cmdclient is to become a new attached, interactive * client. Unless -d is given, the terminal must be opened and then * the client sent MSG_READY. * * 2. If cmdclient is NULL, new-session has been called from an * existing client (such as a key binding). * * 3. Both are NULL, the command was in the configuration file. Treat * this as if -d was given even if it was not. * * In all cases, a new additional session needs to be created and * (unless -d) set as the current session for the client. */ /* Set -d if no client. */ detached = args_has(args, 'd'); if (ctx->cmdclient == NULL && ctx->curclient == NULL) detached = 1; /* * Save the termios settings, part of which is used for new windows in * this session. * * This is read again with tcgetattr() rather than using tty.tio as if * detached, tty_open won't be called. Because of this, it must be done * before opening the terminal as that calls tcsetattr() to prepare for * tmux taking over. */ if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) fatal("tcgetattr failed"); tiop = &tio; } else tiop = NULL; /* Open the terminal if necessary. */ if (!detached && ctx->cmdclient != NULL) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { ctx->error(ctx, "not a terminal"); return (-1); } overrides = options_get_string(&global_s_options, "terminal-overrides"); if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); xfree(cause); return (-1); } } /* Get the new session working directory. */ if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) cwd = ctx->cmdclient->cwd; else { pw = getpwuid(getuid()); if (pw->pw_dir != NULL && *pw->pw_dir != '\0') cwd = pw->pw_dir; else cwd = "/"; } /* Find new session size. */ if (detached) { sx = 80; sy = 24; } else if (ctx->cmdclient != NULL) { sx = ctx->cmdclient->tty.sx; sy = ctx->cmdclient->tty.sy; } else { sx = ctx->curclient->tty.sx; sy = ctx->curclient->tty.sy; } if (sy > 0 && options_get_number(&global_s_options, "status")) sy--; if (sx == 0) sx = 1; if (sy == 0) sy = 1; /* Figure out the command for the new window. */ if (target != NULL) cmd = NULL; else if (args->argc != 0) cmd = args->argv[0]; else cmd = options_get_string(&global_s_options, "default-command"); /* Construct the environment. */ environ_init(&env); update = options_get_string(&global_s_options, "update-environment"); if (ctx->cmdclient != NULL) environ_update(update, &ctx->cmdclient->environ, &env); /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); return (-1); } environ_free(&env); /* Set the initial window name if one given. */ if (cmd != NULL && args_has(args, 'n')) { w = s->curw->window; xfree(w->name); w->name = xstrdup(args_get(args, 'n')); options_set_number(&w->options, "automatic-rename", 0); } /* * If a target session is given, this is to be part of a session group, * so add it to the group and synchronize. */ if (groupwith != NULL) { session_group_add(groupwith, s); session_group_synchronize_to(s); session_select(s, RB_ROOT(&s->windows)->idx); } /* * Set the client to the new session. If a command client exists, it is * taking this session and needs to get MSG_READY and stay around. */ if (!detached) { if (ctx->cmdclient != NULL) { server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); old_s = ctx->cmdclient->session; if (old_s != NULL) ctx->cmdclient->last_session = old_s; ctx->cmdclient->session = s; session_update_activity(s); server_redraw_client(ctx->cmdclient); } else { old_s = ctx->curclient->session; if (old_s != NULL) ctx->curclient->last_session = old_s; ctx->curclient->session = s; session_update_activity(s); server_redraw_client(ctx->curclient); } } recalculate_sizes(); server_update_socket(); /* * If there are still configuration file errors to display, put the new * session's current window into more mode and display them now. */ if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) { wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); window_copy_add(wp, "%s", cause); xfree(cause); } ARRAY_FREE(&cfg_causes); } return (!detached); /* 1 means don't tell command client to exit */ }
/* * Next state. Get next mail. This is also the idle state when completed, so * check for finished mail, exiting, and so on. */ int imap_state_next(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; /* Handle dropped and kept mail. */ if (!ARRAY_EMPTY(&data->dropped)) { if (imap_putln(a, "%u UID STORE %u +FLAGS.SILENT (\\Deleted)", ++data->tag, ARRAY_FIRST(&data->dropped)) != 0) return (FETCH_ERROR); ARRAY_REMOVE(&data->dropped, 0); fctx->state = imap_state_commit; return (FETCH_BLOCK); } if (!ARRAY_EMPTY(&data->kept)) { /* * GMail is broken and does not set the \Seen flag after mail * is fetched, so set it explicitly for kept mail. */ if (imap_putln(a, "%u UID STORE %u +FLAGS.SILENT (\\Seen)", ++data->tag, ARRAY_FIRST(&data->kept)) != 0) return (FETCH_ERROR); ARRAY_REMOVE(&data->kept, 0); fctx->state = imap_state_commit; return (FETCH_BLOCK); } /* Need to purge, switch to purge state. */ if (fctx->flags & FETCH_PURGE) { /* * If can't purge now, loop through this state until there is * no mail on the dropped queue and FETCH_EMPTY is set. Can't * have a seperate state to loop through without returning * here: mail could potentially be added to the dropped list * while in that state. */ if (fctx->flags & FETCH_EMPTY) { fctx->flags &= ~FETCH_PURGE; if (imap_putln(a, "%u EXPUNGE", ++data->tag) != 0) return (FETCH_ERROR); fctx->state = imap_state_expunge; return (FETCH_BLOCK); } /* * Must be waiting for delivery, so permit blocking even though * we (fetch) aren't waiting for any data. */ return (FETCH_BLOCK); } /* If last mail, wait for everything to be committed then close down. */ if (ARRAY_EMPTY(&data->wanted)) { if (data->committed != data->total) return (FETCH_BLOCK); if (imap_putln(a, "%u CLOSE", ++data->tag) != 0) return (FETCH_ERROR); fctx->state = imap_state_close; return (FETCH_BLOCK); } /* Fetch the next mail. */ if (imap_putln(a, "%u " "UID FETCH %u BODY[]",++data->tag, ARRAY_FIRST(&data->wanted)) != 0) return (FETCH_ERROR); fctx->state = imap_state_body; return (FETCH_BLOCK); }
void interpreter::call(const variant & func) { fake * fk = m_fk; const funcunion * f = m_fk->fm.get_func(func); if (UNLIKE(!f)) { FKERR("fkrun no func %s fail", vartostring(&func).c_str()); seterror(m_fk, efk_run_no_func_error, "fkrun no func %s fail", vartostring(&func).c_str()); m_isend = true; return; } // 常规函数 if (f->havefb) { const func_binary * fb = &f->fb; // 空函数处理 if (UNLIKE(!FUNC_BINARY_CMDSIZE(*fb))) { // 所有都完 if (ARRAY_EMPTY(m_stack_list)) { FKLOG("call stack empty end"); m_isend = true; } return; } // 压栈 if (UNLIKE(ARRAY_SIZE(m_stack_list) >= ARRAY_MAX_SIZE(m_stack_list))) { int newsize = ARRAY_MAX_SIZE(m_stack_list) + 1 + ARRAY_MAX_SIZE(m_stack_list) * m_fk->cfg.array_grow_speed / 100; ARRAY_GROW(m_stack_list, newsize, stack); } ARRAY_PUSH_BACK(m_stack_list); stack & s = ARRAY_BACK(m_stack_list); m_cur_stack = &s; STACK_INI(s, m_fk, fb); if (UNLIKE(FUNC_BINARY_MAX_STACK(*fb) > (int)ARRAY_MAX_SIZE(s.m_stack_variant_list))) { ARRAY_GROW(s.m_stack_variant_list, FUNC_BINARY_MAX_STACK(*fb), variant); } // 记录profile beginfuncprofile(); paramstack * ps = getps(m_fk); if (UNLIKE((int)ps->m_variant_list_num != FUNC_BINARY_PARAMNUM(*fb))) { FKERR("call func %s param not match", vartostring(&func).c_str()); seterror(m_fk, efk_run_param_error, "call func %s param not match", vartostring(&func).c_str()); m_isend = true; return; } assert(FUNC_BINARY_PARAMNUM(*fb) <= (int)ARRAY_MAX_SIZE(s.m_stack_variant_list)); // 分配栈空间 for (int i = 0; i < (int)FUNC_BINARY_PARAMNUM(*fb); i++) { SET_STACK(&(ps->m_variant_list[i]), s, i); FKLOG("call set %s to pos %d", (vartostring(&(ps->m_variant_list[i]))).c_str(), i); } ps->clear(); // 重置ret V_SET_NIL(&m_ret[0]); // 标记 FUNC_BINARY_USE(*fb)++; return; } // 记录profile uint32_t s = 0; if (m_fk->pf.isopen()) { s = fkgetmstick(); } // 绑定函数 if (f->haveff) { BIND_FUNC_CALL(f, this); FKLOG("call C func %s", vartostring(&func).c_str()); } // 内置函数 else if (f->havebif) { BUILDIN_FUNC_CALL(f, this); FKLOG("call buildin func %s", vartostring(&func).c_str()); } else { assert(0); FKERR("fkrun no inter func %s fail", vartostring(&func).c_str()); seterror(m_fk, efk_run_no_func_error, "fkrun no inter func %s fail", vartostring(&func).c_str()); m_isend = true; return; } // 返回值 paramstack * theps = getps(m_fk); bool err = false; USE(err); // 这种情况是直接跳过脚本调用了C函数 if (UNLIKE(ARRAY_EMPTY(m_stack_list))) { variant * cret; PS_POP_AND_GET(*theps, cret); m_isend = true; // 直接塞返回值 m_ret[0] = *cret; } // 否则塞到当前堆栈上 else { // 塞返回值 m_cur_stack = &ARRAY_BACK(m_stack_list); const func_binary & fb = *m_cur_stack->m_fb; for (int i = 0; i < m_cur_stack->m_retnum; i++) { variant * ret; GET_VARIANT(*m_cur_stack, fb, ret, m_cur_stack->m_retvpos[i]); variant * cret; PS_GET(*theps, cret, i); *ret = *cret; } } if (UNLIKE(err)) { m_isend = true; } if (m_fk->pf.isopen()) { bool err = false; const char * name = 0; V_GET_STRING(&func, name); m_fk->pf.add_func_sample(name, fkgetmstick() - s); } return; }
/* Check mail against next rule or part of expression. */ int mail_match(struct mail_ctx *mctx, struct msg *msg, struct msgbuf *msgbuf) { struct account *a = mctx->account; struct mail *m = mctx->mail; struct expritem *ei; struct replstrs *users; int should_free, this = -1, error = MAIL_CONTINUE; char desc[DESCBUFSIZE]; set_wrapped(m, ' '); /* If blocked, check for msgs from parent. */ if (mctx->msgid != 0) { if (msg == NULL || msg->id != mctx->msgid) return (MAIL_BLOCKED); mctx->msgid = 0; if (msg->type != MSG_DONE) fatalx("unexpected message"); if (msgbuf->buf != NULL && msgbuf->len != 0) { strb_destroy(&m->tags); m->tags = msgbuf->buf; reset_tags(&m->tags); } ei = mctx->expritem; switch (msg->data.error) { case MATCH_ERROR: return (MAIL_ERROR); case MATCH_TRUE: this = 1; break; case MATCH_FALSE: this = 0; break; default: fatalx("unexpected response"); } apply_result(ei, &mctx->result, this); goto next_expritem; } /* Check for completion and end of ruleset. */ if (mctx->done) return (MAIL_DONE); if (mctx->rule == NULL) { switch (conf.impl_act) { case DECISION_NONE: log_warnx("%s: reached end of ruleset. no " "unmatched-mail option; keeping mail", a->name); m->decision = DECISION_KEEP; break; case DECISION_KEEP: log_debug2("%s: reached end of ruleset. keeping mail", a->name); m->decision = DECISION_KEEP; break; case DECISION_DROP: log_debug2("%s: reached end of ruleset. dropping mail", a->name); m->decision = DECISION_DROP; break; } return (MAIL_DONE); } /* Expression not started. Start it. */ if (mctx->expritem == NULL) { /* Start the expression. */ mctx->result = 0; mctx->expritem = TAILQ_FIRST(mctx->rule->expr); } /* Check this expression item and adjust the result. */ ei = mctx->expritem; /* Handle short-circuit evaluation. */ switch (ei->op) { case OP_NONE: break; case OP_AND: /* And and the result is already false. */ if (!mctx->result) goto next_expritem; break; case OP_OR: /* Or and the result is already true. */ if (mctx->result) goto next_expritem; break; } switch (ei->match->match(mctx, ei)) { case MATCH_ERROR: return (MAIL_ERROR); case MATCH_PARENT: return (MAIL_BLOCKED); case MATCH_TRUE: this = 1; break; case MATCH_FALSE: this = 0; break; default: fatalx("unexpected op"); } apply_result(ei, &mctx->result, this); ei->match->desc(ei, desc, sizeof desc); log_debug3("%s: tried %s, result now %d", a->name, desc, mctx->result); next_expritem: /* Move to the next item. If there is one, then return. */ mctx->expritem = TAILQ_NEXT(mctx->expritem, entry); if (mctx->expritem != NULL) return (MAIL_CONTINUE); log_debug3("%s: finished rule %u, result %d", a->name, mctx->rule->idx, mctx->result); /* If the result was false, skip to find the next rule. */ if (!mctx->result) goto next_rule; log_debug2("%s: matched to rule %u", a->name, mctx->rule->idx); /* * If this rule is stop, mark the context so when we get back after * delivery we know to stop. */ if (mctx->rule->stop) mctx->done = 1; /* Handle nested rules. */ if (!TAILQ_EMPTY(&mctx->rule->rules)) { log_debug2("%s: entering nested rules", a->name); /* * Stack the current rule (we are at the end of it so the * the expritem must be NULL already). */ ARRAY_ADD(&mctx->stack, mctx->rule); /* Continue with the first rule of the nested list. */ mctx->rule = TAILQ_FIRST(&mctx->rule->rules); return (MAIL_CONTINUE); } mctx->matched = 1; /* Handle lambda actions. */ if (mctx->rule->lambda != NULL) { users = find_delivery_users(mctx, NULL, &should_free); chained = MAXACTIONCHAIN; if (fill_from_action(mctx, mctx->rule, mctx->rule->lambda, users) != 0) { if (should_free) ARRAY_FREEALL(users); return (MAIL_ERROR); } if (should_free) ARRAY_FREEALL(users); error = MAIL_DELIVER; } /* Fill the delivery action queue. */ if (!ARRAY_EMPTY(mctx->rule->actions)) { chained = MAXACTIONCHAIN; if (fill_from_strings(mctx, mctx->rule, mctx->rule->actions) != 0) return (MAIL_ERROR); error = MAIL_DELIVER; } next_rule: /* Move to the next rule. */ mctx->ruleidx = mctx->rule->idx; /* save last index */ mctx->rule = TAILQ_NEXT(mctx->rule, entry); /* If no more rules, try to move up the stack. */ while (mctx->rule == NULL) { if (ARRAY_EMPTY(&mctx->stack)) break; log_debug2("%s: exiting nested rules", a->name); mctx->rule = ARRAY_LAST(&mctx->stack); mctx->rule = TAILQ_NEXT(mctx->rule, entry); ARRAY_TRUNC(&mctx->stack, 1); } return (error); }