static char *cleanVersion(cchar *version) { char *cp; cp = strim(version, " \tv=", 0); if (schr(cp, 'X')) { cp = sreplace(cp, "X", "x"); } if (schr(cp, '*')) { cp = sreplace(cp, "*", "x"); } return cp; }
PUBLIC void espDefineAction(HttpRoute *route, cchar *target, void *callback) { EspRoute *eroute; char *action, *controller; assert(route); assert(target && *target); assert(callback); eroute = ((EspRoute*) route->eroute)->top; if (target) { #if DEPRECATED || 1 /* Keep till version 6 */ if (scontains(target, "-cmd-")) { target = sreplace(target, "-cmd-", "/"); } else if (schr(target, '-')) { controller = ssplit(sclone(target), "-", (char**) &action); target = sjoin(controller, "/", action, NULL); } #endif if (!eroute->actions) { eroute->actions = mprCreateHash(-1, MPR_HASH_STATIC_VALUES); } mprAddKey(eroute->actions, target, callback); } }
void KeyframeItem::updateName() { auto s = keyframe_.name = txtName->toPlainText().toStdString(); sreplace(s, {"\r","\n"}, ""); if(s != keyframe_.name) { keyframe_.name = s; txtName->setPlainText(QString::fromStdString(keyframe_.name)); } lblName->setText(txtName->toPlainText()); }
const char *quote_dir(pool *p, char *path) { if (p == NULL || path == NULL) { errno = EINVAL; return NULL; } return sreplace(p, path, "\"", "\"\"", NULL); }
static char *get_config_word(pool *p, char *word) { size_t wordlen; /* Should this word be replaced with a value from the environment? * If so, tmp will contain the expanded value, otherwise tmp will * contain a string duped from the given pool. */ wordlen = strlen(word); if (wordlen > 7) { char *ptr = NULL; /* Does the given word use the environment syntax? We handle this in a * while loop in order to handle a) multiple different variables, and b) * cases where the substituted value is itself a variable. Hopefully no * one is so clever as to want to actually _use_ the latter approach. */ ptr = strstr(word, "%{env:"); while (ptr != NULL) { char *env, *key, *ptr2, *var; unsigned int keylen; pr_signals_handle(); ptr2 = strchr(ptr + 6, '}'); if (ptr2 == NULL) { /* No terminating marker; continue on to the next potential * variable in the word. */ ptr2 = ptr + 6; ptr = strstr(ptr2, "%{env:"); continue; } keylen = (ptr2 - ptr - 6); var = pstrndup(p, ptr, (ptr2 - ptr) + 1); key = pstrndup(p, ptr + 6, keylen); env = pr_env_get(p, key); if (env == NULL) { /* No value in the environment; continue on to the next potential * variable in the word. */ ptr = strstr(ptr2, "%{env:"); continue; } word = (char *) sreplace(p, word, var, env, NULL); ptr = strstr(word, "%{env:"); } } return pstrdup(p, word); }
MODRET wrap_handle_request(cmd_rec *cmd) { /* these variables are names expected to be set by the TCP wrapper code */ struct request_info request; char *user = NULL; config_rec *conf = NULL, *access_conf = NULL, *syslog_conf = NULL; hosts_allow_table = NULL; hosts_deny_table = NULL; /* hide passwords */ session.hide_password = TRUE; /* Sneaky...found in mod_auth.c's cmd_pass() function. Need to find the * login UID in order to resolve the possibly-login-dependent filename. */ user = (char *) get_param_ptr(cmd->server->conf, C_USER, FALSE); /* It's possible that a PASS command came before USER. This is a PRE_CMD * handler, so it won't be protected from this case; we'll need to do * it manually. */ if (!user) return DECLINED(cmd); /* Use mod_auth's _auth_resolve_user() [imported for use here] to get the * right configuration set, since the user may be logging in anonymously, * and the session struct hasn't yet been set for that yet (thus short- * circuiting the easiest way to get the right context...the macros. */ conf = wrap_resolve_user(cmd->pool, &user); /* Search first for user-specific access files. Multiple TCPUserAccessFiles * directives are allowed. */ if ((access_conf = find_config(conf ? conf->subset : CURRENT_CONF, CONF_PARAM, "TCPUserAccessFiles", FALSE)) != NULL) { int matched = FALSE; array_header *user_array = NULL; while (access_conf) { user_array = make_array(cmd->tmp_pool, 0, sizeof(char *)); *((char **) push_array(user_array)) = pstrdup(cmd->tmp_pool, user); /* Check the user expression -- don't forget the offset, to skip * the access file name strings in argv */ if (wrap_eval_expression(((char **) access_conf->argv) + 2, user_array)) { pr_log_debug(DEBUG4, MOD_WRAP_VERSION ": matched TCPUserAccessFiles expression"); matched = TRUE; break; } access_conf = find_config_next(access_conf, access_conf->next, CONF_PARAM, "TCPUserAccessFiles", FALSE); } if (!matched) access_conf = NULL; } /* Next, search for group-specific access files. Multiple * TCPGroupAccessFiles directives are allowed. */ if (!access_conf && (access_conf = find_config(conf ? conf->subset : CURRENT_CONF, CONF_PARAM, "TCPGroupAccessFiles", FALSE)) != NULL) { unsigned char matched = FALSE; /* NOTE: this gid_array is only necessary until Bug#1461 is fixed */ array_header *gid_array = make_array(cmd->pool, 0, sizeof(gid_t)); array_header *group_array = make_array(cmd->pool, 0, sizeof(char *)); while (access_conf) { if (pr_auth_getgroups(cmd->pool, user, &gid_array, &group_array) < 1) { pr_log_debug(DEBUG3, MOD_WRAP_VERSION ": no supplemental groups found for user '%s'", user); } else { /* Check the group expression -- don't forget the offset, to skip * the access file names strings in argv */ if (wrap_eval_expression(((char **) access_conf->argv) + 2, group_array)) { pr_log_debug(DEBUG4, MOD_WRAP_VERSION ": matched TCPGroupAccessFiles expression"); matched = TRUE; break; } } access_conf = find_config_next(access_conf, access_conf->next, CONF_PARAM, "TCPGroupAccessFiles", FALSE); } if (!matched) access_conf = NULL; } /* Finally for globally-applicable access files. Only one such directive * is allowed. */ if (!access_conf) { access_conf = find_config(conf ? conf->subset : CURRENT_CONF, CONF_PARAM, "TCPAccessFiles", FALSE); } if (access_conf) { hosts_allow_table = (char *) access_conf->argv[0]; hosts_deny_table = (char *) access_conf->argv[1]; } /* Now, check the retrieved filename, and see if it requires a login-time * file. */ if (hosts_allow_table != NULL && hosts_allow_table[0] == '~' && hosts_allow_table[1] == '/') { char *allow_real_table = NULL; allow_real_table = wrap_get_user_table(cmd, user, hosts_allow_table); if (!wrap_is_usable_file(allow_real_table)) { pr_log_pri(PR_LOG_WARNING, MOD_WRAP_VERSION ": configured TCPAllowFile %s is unusable", hosts_allow_table); hosts_allow_table = NULL; } else hosts_allow_table = allow_real_table; } if (hosts_deny_table != NULL && hosts_deny_table[0] == '~' && hosts_deny_table[1] == '/') { char *deny_real_table = NULL; deny_real_table = dir_realpath(cmd->pool, hosts_deny_table); if (!wrap_is_usable_file(deny_real_table)) { pr_log_pri(PR_LOG_WARNING, MOD_WRAP_VERSION ": configured TCPDenyFile %s is unusable", hosts_deny_table); hosts_deny_table = NULL; } else hosts_deny_table = deny_real_table; } /* Make sure that _both_ allow and deny TCPAccessFiles are present. * If not, log the missing file, and by default allow request to succeed. */ if (hosts_allow_table != NULL && hosts_deny_table != NULL) { /* Most common case...nothing more necessary */ } else if (hosts_allow_table == NULL && hosts_deny_table != NULL) { /* Log the missing file */ pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": no usable allow access file -- " "allowing connection"); return DECLINED(cmd); } else if (hosts_allow_table != NULL && hosts_deny_table == NULL) { /* log the missing file */ pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": no usable deny access file -- " "allowing connection"); return DECLINED(cmd); } else { /* Neither set -- assume the admin hasn't configured these directives * at all. */ return DECLINED(cmd); } /* Log the names of the allow/deny files being used. */ pr_log_pri(PR_LOG_DEBUG, MOD_WRAP_VERSION ": using access files: %s, %s", hosts_allow_table, hosts_deny_table); /* retrieve the user-defined syslog priorities, if any. Fall back to the * defaults as seen in tcpd.h if not defined. */ syslog_conf = find_config(main_server->conf, CONF_PARAM, "TCPAccessSyslogLevels", FALSE); if (syslog_conf) { allow_severity = (int) syslog_conf->argv[1]; deny_severity = (int) syslog_conf->argv[2]; } else { allow_severity = PR_LOG_INFO; deny_severity = PR_LOG_WARNING; } pr_log_debug(DEBUG4, MOD_WRAP_VERSION ": checking under service name '%s'", wrap_service_name); request_init(&request, RQ_DAEMON, wrap_service_name, RQ_FILE, session.c->rfd, 0); fromhost(&request); if (STR_EQ(eval_hostname(request.client), paranoid) || !hosts_access(&request)) { char *denymsg = NULL; /* log the denied connection */ wrap_log_request_denied(deny_severity, &request); /* check for AccessDenyMsg */ if ((denymsg = (char *) get_param_ptr(TOPLEVEL_CONF, "AccessDenyMsg", FALSE)) != NULL) denymsg = sreplace(cmd->tmp_pool, denymsg, "%u", user, NULL); if (denymsg) return ERROR_MSG(cmd, R_530, denymsg); else return ERROR_MSG(cmd, R_530, "Access denied."); } /* If request is allowable, return DECLINED (for engine to act as if this * handler was never called, else ERROR (for engine to abort processing and * deny request. */ wrap_log_request_allowed(allow_severity, &request); return DECLINED(cmd); }
char *mreplace(char *string, char *se,char *rep) { int status,i; char noMatch=0; regex_t re; size_t nmatch = 16; regmatch_t pm[nmatch]; unsigned long offset = 0; char field[16]; char *res; memChunk *search,*temp,*found,*ffound; if(!string) return ""; if(!strlen(se)) return string; if(!strcmp(se,rep)) return string; temp = memStringReserve(string,INPUTLINE_BUFFER_REPLACE_SIZE); search = memStringReserve(se,INPUTLINE_BUFFER_REPLACE_SIZE); sreplace(search->address,"\\d","[0-9]",1,INPUTLINE_BUFFER_REPLACE_SIZE); #if MDEBUG2 sData=strdup(string); DBG("mreplace(string,se,re)","string : %s",sData); DBG("mreplace(string,se,re)","search : %s",search->address); DBG("mreplace(string,se,re)","replace : %s",rep); #endif if(regcomp(&re, search->address, REG_EXTENDED) != 0) if(regcomp(&re, search->address, REG_EXTENDED<<1)) noMatch=1; if((status = regexec(&re, string, nmatch, pm, 0))) noMatch=1; if(noMatch) { memFree(temp); memFree(search); return (char*)string; } found = memReserve(INPUTLINE_BUFFER_REPLACE_SIZE); ffound = memReserve(INPUTLINE_BUFFER_REPLACE_SIZE); while(!status) { offset=strlen(temp->address)-strlen(string); snprintf(found->address, INPUTLINE_BUFFER_REPLACE_SIZE, "%.*s", (int)(size_t)(pm[0].rm_eo - pm[0].rm_so), &string[pm[0].rm_so]);//,&string[pm[0].rm_so]); #if MDEBUG3 printf("------->> found \"%s\" length => %d offset[%d]\n", found->address, strlen(temp->address),offset); #endif sreplace(temp->address+offset,found->address,rep,0,INPUTLINE_BUFFER_REPLACE_SIZE-offset); for(i=1; i<nmatch; i++) { snprintf(ffound->address,INPUTLINE_BUFFER_REPLACE_SIZE, "%.*s", (int)(size_t)(pm[i].rm_eo - pm[i].rm_so), &string[pm[i].rm_so]);//,&string[pm[i].rm_so]); snprintf(field,sizeof(field),"\\%d",i); if(strlen(ffound->address)) { sreplace(temp->address,field,ffound->address,1,INPUTLINE_BUFFER_REPLACE_SIZE); } else { sreplace(temp->address,field,"",1,INPUTLINE_BUFFER_REPLACE_SIZE); continue; } #if MDEBUG3 printf(">> subfound %2d '%s' => '%s' length %d\n", i, ffound->address, temp->address,offset); #endif } if(offset<0) offset=-offset; if(*string && strlen(string+pm[0].rm_eo)) { string+=pm[0].rm_eo; status = regexec(&re, string, nmatch, pm, 0); } else { status=-1; } } #if MDEBUG2 DBG("mreplace(string,se,re)","result : %s",temp->address); #endif res=strdup(temp->address); memFree(temp); memFree(search); memFree(found); memFree(ffound); return res; }
static bool inRange(MprVersion *vp, cchar *expr) { char *cp, *ver, *op, *base, *pre, *all; cchar *high, *low; uint64 factor, min, max, num; while (isspace((uchar) *expr)) expr++; if (srmatch(expr, semExpr, &all, &op, &ver, NULL) <= 0) { mprLog("error", 5, "Bad version expression: %s", expr); return 0; } if (smatch(op, "~")) { /* ~VER Compatible with VER at the level of specificity given. ~1.2.3 == (>=1.2.3 <1.3.0) Compatible at the patch level ~1.2 == 1.2.x Compatible at the minor level ~1 == 1.x Compatible at the major level */ if (partCount(ver) == 3 && (cp = srchr(ver, '.')) != 0) { high = sjoin(snclone(ver, cp - ver), ".", MAX_VER_STR, NULL); if ((cp = schr(ver, '-')) != 0) { high = sjoin(high, cp, NULL); } return inRange(vp, sjoin(">=", ver, NULL)) && inRange(vp, sjoin("<", high, NULL)); } return inRange(vp, completeVersion(ver, "x")); } if (smatch(op, "^")) { /* ^VER Compatible with VER at the most significant level. ^0.2.3 == 0.2.3 <= VER < 0.3.0 ^1.2.3 == 1.2.3 <= VER < 2.0.0 So convert to a range */ high = ver; for (cp = ver, factor = VER_FACTOR * VER_FACTOR; *cp; cp++) { if (*cp == '.') { factor /= VER_FACTOR; } else if (isdigit((uchar) *cp) && *cp != '0') { num = (stoi(cp) + 1) * factor; high = numberToVersion(num); if ((cp = schr(ver, '-')) != 0) { high = sjoin(high, cp, NULL); } break; } } return inRange(vp, sjoin(">=", ver, NULL)) && inRange(vp, sjoin("<", high, NULL)); } ver = completeVersion(ver, "x"); if (srmatch(ver, semCriteria, &all, &base, &pre, NULL) <= 0) { mprLog("error", 5, "Cannot match version %s", ver); return 0; } if (vp->preVersion) { if (!pre) { return 0; } if (snumber(vp->preVersion)) { if (stoi(pre) < stoi(vp->preVersion)) { return 0; } } else { if (scmp(pre, vp->preVersion) < 0 && !smatch(pre, "-")) { return 0; } } } min = 0; max = MAX_VER * VER_FACTOR * VER_FACTOR; if (schr(ver, 'x')) { if (smatch(op, ">=")) { // 1.2.3 >= 2.x.x ... 1.2.3 >= 2.0.0 low = sreplace(ver, "x", "0"); min = versionToNumber(low); } else if (smatch(op, "<=")) { // 1.2.3 < 2.x.x ... 1.2.3 <2.MAX.MAX high = sreplace(ver, "x", MAX_VER_STR); max = versionToNumber(high); } else if (*op == '>') { // 1.2.3 > 2.x.x ... 1.2.3 > 2.0.0 low = sreplace(ver, "x", "0"); min = versionToNumber(low) + 1; } else if (*op == '<') { // 1.2.3 < 2.x.x ... 1.2.3 <2.MAX.MAX high = sreplace(ver, "x", MAX_VER_STR); max = versionToNumber(high) - 1; } else { low = sreplace(ver, "x", "0"); high = sreplace(ver, "x", MAX_VER_STR); return inRange(vp, sjoin(">=", low, NULL)) && inRange(vp, sjoin("<", high, NULL)); } } else if (smatch(op, ">=")) { min = versionToNumber(base); } else if (smatch(op, "<=")) { max = versionToNumber(base); } else if (*op == '>') { min = versionToNumber(base) + 1; } else if (*op == '<') { max = versionToNumber(base) - 1; } else { min = max = versionToNumber(base); } if (min <= vp->numberVersion && vp->numberVersion <= max) { return 1; } return 0; }
static char *get_config_word(pool *p, char *word) { size_t wordlen; /* Should this word be replaced with a value from the environment? * If so, tmp will contain the expanded value, otherwise tmp will * contain a string duped from the given pool. */ wordlen = strlen(word); if (wordlen > 7) { char *ptr = NULL; /* Does the given word use the environment syntax? * * In the simple (and most common) case, the entire word is the variable * syntax. But we also need to check for cases where the environment * variable syntax is embedded within the word string. */ if (strncmp(word, "%{env:", 6) == 0 && word[wordlen-1] == '}') { char *env; word[wordlen-1] = '\0'; env = pr_env_get(p, word + 6); return env ? pstrdup(p, env) : ""; } /* This is in a while loop in order to handle a) multiple different * variables, and b) cases where the substituted value is itself a * variable. (Hopefully no one is so clever as to want to actually * _use_ the latter approach.) */ ptr = strstr(word, "%{env:"); while (ptr != NULL) { char *env, *key, *ptr2, *var; unsigned int keylen; pr_signals_handle(); ptr2 = strchr(ptr + 6, '}'); if (ptr2 == NULL) { /* No terminating marker; continue on to the next potential * variable in the word. */ ptr2 = ptr + 6; ptr = strstr(ptr2, "%{env:"); continue; } keylen = (ptr2 - ptr - 6); var = pstrndup(p, ptr, (ptr2 - ptr) + 1); key = pstrndup(p, ptr + 6, keylen); env = pr_env_get(p, key); if (env == NULL) { /* No value in the environment; continue on to the next potential * variable in the word. */ ptr = strstr(ptr2, "%{env:"); continue; } word = (char *) sreplace(p, word, var, env, NULL); ptr = strstr(word, "%{env:"); } } return pstrdup(p, word); }
void pr_session_send_banner(server_rec *s, int flags) { config_rec *c = NULL; char *display = NULL; const char *serveraddress = NULL; config_rec *masq = NULL; display = get_param_ptr(s->conf, "DisplayConnect", FALSE); if (display != NULL) { if (pr_display_file(display, NULL, R_220, flags) < 0) { pr_log_debug(DEBUG6, "unable to display DisplayConnect file '%s': %s", display, strerror(errno)); } } serveraddress = pr_netaddr_get_ipstr(session.c->local_addr); masq = find_config(s->conf, CONF_PARAM, "MasqueradeAddress", FALSE); if (masq != NULL) { pr_netaddr_t *masq_addr = (pr_netaddr_t *) masq->argv[0]; serveraddress = pr_netaddr_get_ipstr(masq_addr); } c = find_config(s->conf, CONF_PARAM, "ServerIdent", FALSE); if (c == NULL || *((unsigned char *) c->argv[0]) == TRUE) { unsigned char *defer_welcome; defer_welcome = get_param_ptr(s->conf, "DeferWelcome", FALSE); if (c && c->argc > 1) { char *server_ident = c->argv[1]; if (strstr(server_ident, "%L") != NULL) { server_ident = sreplace(session.pool, server_ident, "%L", serveraddress, NULL); } if (strstr(server_ident, "%V") != NULL) { server_ident = sreplace(session.pool, server_ident, "%V", main_server->ServerFQDN, NULL); } if (strstr(server_ident, "%v") != NULL) { server_ident = sreplace(session.pool, server_ident, "%v", main_server->ServerName, NULL); } if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, "%s", server_ident); } else { pr_response_add(R_220, "%s", server_ident); } } else if (defer_welcome && *defer_welcome == TRUE) { if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server ready."); } else { pr_response_add(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server ready."); } } else { if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server (%s) [%s]", s->ServerName, serveraddress); } else { pr_response_add(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server (%s) [%s]", s->ServerName, serveraddress); } } } else { if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, _("%s FTP server ready"), serveraddress); } else { pr_response_add(R_220, _("%s FTP server ready"), serveraddress); } } }
const char *sftp_display_fh_get_msg(pool *p, pr_fh_t *fh) { struct stat st; char buf[PR_TUNABLE_BUFFER_SIZE], *msg = ""; int len, res; unsigned int *current_clients = NULL; unsigned int *max_clients = NULL; off_t fs_size = 0; void *v; const char *serverfqdn = main_server->ServerFQDN; char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'}, mg_max[12] = "unlimited"; char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'}, mg_cur_class[12] = {'\0'}; const char *mg_time; char *rfc1413_ident = NULL, *user = NULL; /* Stat the opened file to determine the optimal buffer size for IO. */ memset(&st, 0, sizeof(st)); if (pr_fsio_fstat(fh, &st) == 0) { fh->fh_iosz = st.st_blksize; } res = pr_fs_fgetsize(fh->fh_fd, &fs_size); if (res < 0 && errno != ENOSYS) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error getting filesystem size for '%s': %s", fh->fh_path, strerror(errno)); fs_size = 0; } snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size); format_size_str(mg_size_units, sizeof(mg_size_units), fs_size); mg_time = pr_strtime(time(NULL)); max_clients = get_param_ptr(main_server->conf, "MaxClients", FALSE); v = pr_table_get(session.notes, "client-count", NULL); if (v) { current_clients = v; } snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1); if (session.conn_class != NULL && session.conn_class->cls_name) { unsigned int *class_clients = NULL; config_rec *maxc = NULL; unsigned int maxclients = 0; v = pr_table_get(session.notes, "class-client-count", NULL); if (v) { class_clients = v; } snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", class_clients ? *class_clients : 0); /* For the %z variable, first we scan through the MaxClientsPerClass, * and use the first applicable one. If none are found, look for * any MaxClients set. */ maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass", FALSE); while (maxc) { pr_signals_handle(); if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) { maxc = find_config_next(maxc, maxc->next, CONF_PARAM, "MaxClientsPerClass", FALSE); continue; } maxclients = *((unsigned int *) maxc->argv[1]); break; } if (maxclients == 0) { maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE); if (maxc) maxclients = *((unsigned int *) maxc->argv[0]); } snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients); } else { snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", max_clients ? *max_clients : 0); snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0); } snprintf(mg_max, sizeof(mg_max), "%u", max_clients ? *max_clients : 0); user = pr_table_get(session.notes, "mod_auth.orig-user", NULL); if (user == NULL) user = ""; rfc1413_ident = pr_table_get(session.notes, "mod_ident.rfc1413-ident", NULL); if (rfc1413_ident == NULL) { rfc1413_ident = "UNKNOWN"; } memset(buf, '\0', sizeof(buf)); while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) { char *tmp; pr_signals_handle(); buf[sizeof(buf)-1] = '\0'; len = strlen(buf); while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) { pr_signals_handle(); buf[len-1] = '\0'; len--; } /* Check for any Variable-type strings. */ tmp = strstr(buf, "%{"); while (tmp) { char *key, *tmp2; const char *val; pr_signals_handle(); tmp2 = strchr(tmp, '}'); if (tmp2 == NULL) { /* No closing '}' found in this string, so no need to look for any * aother '%{' opening sequence. Just move on. */ tmp = NULL; break; } key = pstrndup(p, tmp, tmp2 - tmp + 1); /* There are a couple of special-case keys to watch for: * * env:$var * time:$fmt * * The Var API does not easily support returning values for keys * where part of the value depends on part of the key. That's why * these keys are handled here, instead of in pr_var_get(). */ if (strncmp(key, "%{time:", 7) == 0) { char time_str[128], *fmt; time_t now; struct tm *time_info; fmt = pstrndup(p, key + 7, strlen(key) - 8); now = time(NULL); time_info = pr_localtime(NULL, &now); memset(time_str, 0, sizeof(time_str)); strftime(time_str, sizeof(time_str), fmt, time_info); val = pstrdup(p, time_str); } else if (strncmp(key, "%{env:", 6) == 0) { char *env_var; env_var = pstrndup(p, key + 6, strlen(key) - 7); val = pr_env_get(p, env_var); if (val == NULL) { pr_trace_msg("var", 4, "no value set for environment variable '%s', using \"(none)\"", env_var); val = "(none)"; } } else { val = pr_var_get(key); if (val == NULL) { pr_trace_msg("var", 4, "no value set for name '%s', using \"(none)\"", key); val = "(none)"; } } outs = sreplace(p, buf, key, val, NULL); sstrncpy(buf, outs, sizeof(buf)); tmp = strstr(outs, "%{"); } outs = sreplace(p, buf, "%C", (session.cwd[0] ? session.cwd : "(none)"), "%E", main_server->ServerAdmin, "%F", mg_size, "%f", mg_size_units, "%i", "0", "%K", "0", "%k", "0B", "%L", serverfqdn, "%M", mg_max, "%N", mg_cur, "%o", "0", "%R", (session.c && session.c->remote_name ? session.c->remote_name : "(unknown)"), "%T", mg_time, "%t", "0", "%U", user, "%u", rfc1413_ident, "%V", main_server->ServerName, "%x", session.conn_class ? session.conn_class->cls_name : "(unknown)", "%y", mg_cur_class, "%z", mg_class_limit, NULL); /* Always make sure that the lines we send are CRLF-terminated. */ msg = pstrcat(p, msg, outs, "\r\n", NULL); /* Clear the buffer for the next read. */ memset(buf, '\0', sizeof(buf)); } return msg; }
/* Convert an ESP web page into C code Directives: <%@ include "file" Include an esp file <%@ layout "file" Specify a layout page to use. Use layout "" to disable layout management <%@ content Mark the location to substitute content in a layout pag <% Begin esp section containing C code <%^ global Put esp code at the global level <%^ start Put esp code at the start of the function <%^ end Put esp code at the end of the function <%= Begin esp section containing an expression to evaluate and substitute <%= [%fmt] Begin a formatted expression to evaluate and substitute. Format is normal printf format. Use %S for safe HTML escaped output. %> End esp section -%> End esp section and trim trailing newline @@var Substitue the value of a variable. Var can also be simple expressions (without spaces) @#field Lookup the current record for the value of the field. */ char *espBuildScript(HttpRoute *route, cchar *page, cchar *path, cchar *cacheName, cchar *layout, char **err) { EspParse parse; char *control, *incBuf, *incText, *global, *token, *body, *where; char *rest, *start, *end, *include, *line, *fmt, *layoutPage, *layoutBuf; ssize len; int tid; mprAssert(page); body = start = end = global = ""; *err = 0; memset(&parse, 0, sizeof(parse)); parse.data = (char*) page; parse.next = parse.data; if ((parse.token = mprCreateBuf(-1, -1)) == 0) { return 0; } tid = getEspToken(&parse); while (tid != ESP_TOK_EOF) { token = mprGetBufStart(parse.token); #if FUTURE if (parse.lineNumber != lastLine) { body = sfmt("\n# %d \"%s\"\n", parse.lineNumber, path); } #endif switch (tid) { case ESP_TOK_CODE: if (*token == '^') { for (token++; *token && isspace((int) *token); token++) ; where = stok(token, " \t\r\n", &rest); if (rest == 0) { ; } else if (scmp(where, "global") == 0) { global = sjoin(global, rest, NULL); } else if (scmp(where, "start") == 0) { if (*start == '\0') { start = " "; } start = sjoin(start, rest, NULL); } else if (scmp(where, "end") == 0) { if (*end == '\0') { end = " "; } end = sjoin(end, rest, NULL); } } else { body = sjoin(body, token, NULL); } break; case ESP_TOK_CONTROL: /* NOTE: layout parsing not supported */ control = stok(token, " \t\r\n", &token); if (scmp(control, "content") == 0) { body = sjoin(body, CONTENT_MARKER, NULL); } else if (scmp(control, "include") == 0) { if (token == 0) { token = ""; } token = strim(token, " \t\r\n\"", MPR_TRIM_BOTH); token = mprNormalizePath(token); if (token[0] == '/') { include = sclone(token); } else { include = mprJoinPath(mprGetPathDir(path), token); } if ((incText = mprReadPathContents(include, &len)) == 0) { *err = sfmt("Can't read include file: %s", include); return 0; } /* Recurse and process the include script */ incBuf = 0; if ((incBuf = espBuildScript(route, incText, include, NULL, NULL, err)) == 0) { return 0; } body = sjoin(body, incBuf, NULL); } else if (scmp(control, "layout") == 0) { token = strim(token, " \t\r\n\"", MPR_TRIM_BOTH); if (*token == '\0') { layout = 0; } else { token = mprNormalizePath(token); if (token[0] == '/') { layout = sclone(token); } else { layout = mprJoinPath(mprGetPathDir(path), token); } if (!mprPathExists(layout, F_OK)) { *err = sfmt("Can't access layout page %s", layout); return 0; } } } else { *err = sfmt("Unknown control %s at line %d", control, parse.lineNumber); return 0; } break; case ESP_TOK_ERR: return 0; case ESP_TOK_EXPR: /* <%= expr %> */ if (*token == '%') { fmt = stok(token, ": \t\r\n", &token); if (token == 0) { token = ""; } } else { fmt = "%s"; } token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); body = sjoin(body, " espRender(conn, \"", fmt, "\", ", token, ");\n", NULL); break; case ESP_TOK_FIELD: /* @#field */ token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); body = sjoin(body, " espRender(conn, getField(\"", token, "\"));\n", NULL); break; case ESP_TOK_LITERAL: line = joinLine(token, &len); body = sfmt("%s espRenderBlock(conn, \"%s\", %d);\n", body, line, len); break; case ESP_TOK_VAR: /* @@var */ token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); /* espRenderParam uses espRenderSafeString */ body = sjoin(body, " espRenderParam(conn, \"", token, "\");\n", NULL); break; default: return 0; } tid = getEspToken(&parse); } if (cacheName) { /* CacheName will only be set for the outermost invocation */ if (layout && mprPathExists(layout, R_OK)) { if ((layoutPage = mprReadPathContents(layout, &len)) == 0) { *err = sfmt("Can't read layout page: %s", layout); return 0; } layoutBuf = 0; if ((layoutBuf = espBuildScript(route, layoutPage, layout, NULL, NULL, err)) == 0) { return 0; } body = sreplace(layoutBuf, CONTENT_MARKER, body); } if (start && start[slen(start) - 1] != '\n') { start = sjoin(start, "\n", NULL); } if (end && end[slen(end) - 1] != '\n') { end = sjoin(end, "\n", NULL); } mprAssert(slen(path) > slen(route->dir)); mprAssert(sncmp(path, route->dir, slen(route->dir)) == 0); if (sncmp(path, route->dir, slen(route->dir)) == 0) { path = &path[slen(route->dir) + 1]; } body = sfmt(\ "/*\n Generated from %s\n */\n"\ "#include \"esp-app.h\"\n"\ "%s\n"\ "static void %s(HttpConn *conn) {\n"\ "%s%s%s"\ "}\n\n"\ "%s int esp_%s(HttpRoute *route, MprModule *module) {\n"\ " espDefineView(route, \"%s\", %s);\n"\ " return 0;\n"\ "}\n", path, global, cacheName, start, body, end, ESP_EXPORT_STRING, cacheName, mprGetPortablePath(path), cacheName); mprLog(6, "Create ESP script: \n%s\n", body); } return body; }