/* * Syntax: testucs [w|n] * * If arg is not recognized, run both tests. */ int main(int argc, char **argv) { struct testval s; memset (&s, 0, sizeof(s)); if (argc < 2 || apr_tolower(*argv[1]) != 'w') { printf ("\n\nTesting Narrow Char Ranges\n"); test_nrange(&s); } if (argc < 2 || apr_tolower(*argv[1]) != 'n') { printf ("\n\nTesting Wide Char Ranges\n"); test_wrange(&s); } return 0; }
int strcasecmp(const char *a, const char *b) { const char *p = a; const char *q = b; for (p = a, q = b; *p && *q; p++, q++) { int diff = apr_tolower(*p) - apr_tolower(*q); if (diff) return diff; } if (*p) return 1; /* p was longer than q */ if (*q) return -1; /* p was shorter than q */ return 0; /* Exact match */ }
static int store_header_in_dict(void *baton, const char *key, const char *header) { auth_baton_t *ab = baton; const char *auth_attr; char *auth_name, *c; /* We're only interested in xxxx-Authenticate headers. */ if (strcasecmp(key, ab->header) != 0) return 0; /* Extract the authentication scheme name. */ auth_attr = strchr(header, ' '); if (auth_attr) { auth_name = apr_pstrmemdup(ab->pool, header, auth_attr - header); } else auth_name = apr_pstrmemdup(ab->pool, header, strlen(header)); /* Convert scheme name to lower case to enable case insensitive matching. */ for (c = auth_name; *c != '\0'; c++) *c = (char)apr_tolower(*c); apr_hash_set(ab->hdrs, auth_name, APR_HASH_KEY_STRING, apr_pstrdup(ab->pool, header)); return 0; }
/* Canonicalize a string for hashing. Modifies KEY in place. */ static APR_INLINE char * make_hash_key(char *key) { register char *p; for (p = key; *p != 0; ++p) *p = (char)apr_tolower(*p); return key; }
int strncasecmp(const char *a, const char *b, size_t n) { const char *p = a; const char *q = b; for (p = a, q = b; /*NOTHING */ ; p++, q++) { int diff; if (p == a + n) return 0; /* Match up to n characters */ if (!(*p && *q)) return *p - *q; diff = apr_tolower(*p) - apr_tolower(*q); if (diff) return diff; } /*NOTREACHED */ }
char *lowerstr(apr_pool_t *pool, const char *input) { char *temp; char *itr; temp = apr_pstrdup(pool, input); for (itr=temp; *itr!='\0'; itr++) { *itr = apr_tolower(*itr); } return temp; }
static apr_status_t iconv_getpath(char *buf, const char *name, apr_pool_t *ctx) { char buffer[APR_PATH_MAX]; apr_array_header_t *pathelts; apr_pool_t *subpool; apr_status_t status; char *ptr; status = apr_pool_create(&subpool, ctx); if (status) return status; if (apr_tolower(name[0]) == 'x' && name[1] == '-') name += 2; ptr = buffer; while (0 != (*ptr++ = apr_tolower(*name++))) ; /* Fall back on APR_ICONV_PATH if APR_ICONVn_PATH isn't set... * TODO: Drop support for "APR_ICONV_PATH" in apr-iconv 2.0 */ if ((!apr_env_get(&ptr, APR_ICONV_PATH, subpool) || (!apr_env_get(&ptr, "APR_ICONV_PATH", subpool))) && !apr_filepath_list_split(&pathelts, ptr, subpool)) { int i; char **elts = (char **)pathelts->elts; for (i = 0; i < pathelts->nelts; ++i) { if (iconv_getpathname(buf, elts[i], buffer, subpool) == 0) { apr_pool_destroy(subpool); return APR_SUCCESS; } } } status = iconv_getpathname(buf, ICONV_DEFAULT_PATH, buffer, subpool); apr_pool_destroy(subpool); return status; }
static sp_reason spdist(const char *s, const char *t) { for (; apr_tolower(*s) == apr_tolower(*t); t++, s++) { if (*t == '\0') { return SP_MISCAPITALIZED; /* exact match (sans case) */ } } if (*s) { if (*t) { if (s[1] && t[1] && apr_tolower(*s) == apr_tolower(t[1]) && apr_tolower(*t) == apr_tolower(s[1]) && strcasecmp(s + 2, t + 2) == 0) { return SP_TRANSPOSITION; /* transposition */ } if (strcasecmp(s + 1, t + 1) == 0) { return SP_SIMPLETYPO; /* 1 char mismatch */ } } if (strcasecmp(s + 1, t) == 0) { return SP_EXTRACHAR; /* extra character */ } } if (*t && strcasecmp(s, t + 1) == 0) { return SP_MISSINGCHAR; /* missing character */ } return SP_VERYDIFFERENT; /* distance too large to fix. */ }
static const char *match_boyer_moore_horspool_nocase( const apr_strmatch_pattern *this_pattern, const char *s, apr_size_t slen) { const char *s_end = s + slen; int *shift = (int *)(this_pattern->context); const char *s_next = s + this_pattern->length - 1; const char *p_start = this_pattern->pattern; const char *p_end = p_start + this_pattern->length - 1; while (s_next < s_end) { const char *s_tmp = s_next; const char *p_tmp = p_end; while (apr_tolower(*s_tmp) == apr_tolower(*p_tmp)) { p_tmp--; if (p_tmp < p_start) { return s_tmp; } s_tmp--; } s_next += shift[(unsigned char)apr_tolower(*s_next)]; } return NULL; }
/* Return the value for KEY in HASH. If CASE_SENSITIVE is FALSE, BUFFER will be used to construct the normalized hash key. */ static void * get_hash_value(apr_hash_t *hash, svn_stringbuf_t *buffer, const char *key, svn_boolean_t case_sensitive) { apr_size_t i; apr_size_t len = strlen(key); if (case_sensitive) return apr_hash_get(hash, key, len); svn_stringbuf_ensure(buffer, len); for (i = 0; i < len; ++i) buffer->data[i] = (char)apr_tolower(key[i]); return apr_hash_get(hash, buffer->data, len); }
APU_DECLARE(const apr_strmatch_pattern *) apr_strmatch_precompile( apr_pool_t *p, const char *s, int case_sensitive) { apr_strmatch_pattern *pattern; apr_size_t i; int *shift; pattern = apr_palloc(p, sizeof(*pattern)); pattern->pattern = s; pattern->length = strlen(s); if (pattern->length == 0) { pattern->compare = match_no_op; pattern->context = NULL; return pattern; } shift = (int *)apr_palloc(p, sizeof(int) * NUM_CHARS); for (i = 0; i < NUM_CHARS; i++) { shift[i] = pattern->length; } if (case_sensitive) { pattern->compare = match_boyer_moore_horspool; for (i = 0; i < pattern->length - 1; i++) { shift[(unsigned char)s[i]] = pattern->length - i - 1; } } else { pattern->compare = match_boyer_moore_horspool_nocase; for (i = 0; i < pattern->length - 1; i++) { shift[(unsigned char)apr_tolower(s[i])] = pattern->length - i - 1; } } pattern->context = shift; return pattern; }
/* Routine to perform the actual construction and execution of the relevant * INSERT statements. */ static int log_sql_transaction(request_rec *orig) { char **ptrptr, **ptrptr2; logsql_state *cls = ap_get_module_config(orig->server->module_config, &log_sql_module); const char *access_query; request_rec *r; const char *transfer_tablename = cls->transfer_table_name; const char *notes_tablename = cls->notes_table_name; const char *hout_tablename = cls->hout_table_name; const char *hin_tablename = cls->hin_table_name; const char *cookie_tablename = cls->cookie_table_name; if (global_config.driver == NULL) { return OK; } /* We handle mass virtual hosting differently. Dynamically determine the name * of the table from the virtual server's name, and flag it for creation. */ if (global_config.massvirtual) { /* TODO: Make these configurable? */ char *access_base = "access_"; char *notes_base = "notes_"; char *hout_base = "headout_"; char *hin_base = "headin_"; char *cookie_base = "cookies_"; /* Determine the hostname and convert it to all lower-case; */ char *servername = apr_pstrdup(orig->pool,(char *)ap_get_server_name(orig)); char *p=servername; while (*p) { *p = apr_tolower(*p); if (*p == '.') *p = '_'; if (*p == '-') *p = '_'; ++p; } /* Find memory long enough to hold the table name + \0. */ transfer_tablename = apr_pstrcat(orig->pool, access_base, servername, NULL); notes_tablename = apr_pstrcat(orig->pool, notes_base, servername, NULL); hin_tablename = apr_pstrcat(orig->pool, hin_base, servername, NULL); hout_tablename = apr_pstrcat(orig->pool, hout_base, servername, NULL); cookie_tablename = apr_pstrcat(orig->pool, cookie_base, servername, NULL); /* Tell this virtual server its transfer table name, and * turn on create_tables, which is implied by massvirtual. */ global_config.createtables = 1; } /* Do we have enough info to log? */ if (!transfer_tablename) { return DECLINED; } else { const char *thehost; const char *theitem; char *fields = "", *values = ""; char *itemsets = ""; char *note_query = NULL; char *hin_query = NULL; char *hout_query = NULL; char *cookie_query = NULL; const char *unique_id; const char *formatted_item; int i,length; int proceed; for (r = orig; r->next; r = r->next) { continue; } /* The following is a stolen upsetting mess of pointers, I'm sorry. * Anyone with the motiviation and/or the time should feel free * to make this cleaner. :) */ ptrptr2 = (char **) (cls->transfer_accept_list->elts + (cls->transfer_accept_list->nelts * cls->transfer_accept_list->elt_size)); /* Go through each element of the accept list and compare it to the * request_uri. If we don't get a match, return without logging */ if ((r->uri) && (cls->transfer_accept_list->nelts)) { proceed = 0; for (ptrptr = (char **) cls->transfer_accept_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_accept_list->elt_size)) if (ap_strstr(r->uri, *ptrptr)) { proceed = 1; break; } if (!proceed) return OK; } /* Go through each element of the ignore list and compare it to the * request_uri. If we get a match, return without logging */ ptrptr2 = (char **) (cls->transfer_ignore_list->elts + (cls->transfer_ignore_list->nelts * cls->transfer_ignore_list->elt_size)); if (r->uri) { for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) if (ap_strstr(r->uri, *ptrptr)) { return OK; } } /* Go through each element of the ignore list and compare it to the * remote host. If we get a match, return without logging */ ptrptr2 = (char **) (cls->remhost_ignore_list->elts + (cls->remhost_ignore_list->nelts * cls->remhost_ignore_list->elt_size)); thehost = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME, NULL); if (thehost) { for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) if (ap_strstr(thehost, *ptrptr)) { return OK; } } /* Iterate through the format characters and set up the INSERT string according to * what the user has configured. */ length = strlen(cls->transfer_log_format); for (i = 0; i<length; i++) { logsql_item *item = cls->parsed_log_format[i]; if (item==NULL) { log_error(APLOG_MARK, APLOG_ERR, 0, orig->server, "Log Format '%c' unknown",cls->transfer_log_format[i]); continue; } /* Yes, this key is one of the configured keys. * Call the key's function and put the returned value into 'formatted_item' */ formatted_item = item->func(item->want_orig_default ? orig : r, ""); /* Massage 'formatted_item' for proper SQL eligibility... */ if (!formatted_item) { formatted_item = ""; } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !item->string_contents) { /* If apache tried to log a '-' character for a numeric field, convert that to a zero * because the database expects a numeral and will reject the '-' character. */ formatted_item = "0"; } /* Append the fieldname and value-to-insert to the appropriate strings, quoting stringvals with ' as appropriate */ fields = apr_pstrcat(r->pool, fields, (i ? "," : ""), item->sql_field_name, NULL); values = apr_pstrcat(r->pool, values, (i ? "," : ""), global_config.driver->escape(formatted_item, r->pool,&global_config.db), NULL); } /* Work through the list of notes defined by LogSQLWhichNotes */ i = 0; unique_id = extract_unique_id(r, ""); ptrptr2 = (char **) (cls->notes_list->elts + (cls->notes_list->nelts * cls->notes_list->elt_size)); for (ptrptr = (char **) cls->notes_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->notes_list->elt_size)) { /* If the specified note (*ptrptr) exists for the current request... */ if ((theitem = apr_table_get(r->notes, *ptrptr))) { itemsets = apr_pstrcat(r->pool, itemsets, (i > 0 ? "," : ""), "(", global_config.driver->escape(unique_id, r->pool, &global_config.db), ",", global_config.driver->escape(*ptrptr, r->pool,&global_config.db), ",", global_config.driver->escape(theitem, r->pool,&global_config.db), ")", NULL); i++; } } if ( *itemsets != '\0' ) { note_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s", /*global_config.insertdelayed?"delayed":*/"", notes_tablename, itemsets); log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: note string: %s", note_query); } /* Work through the list of headers-out defined by LogSQLWhichHeadersOut*/ i = 0; itemsets = ""; ptrptr2 = (char **) (cls->hout_list->elts + (cls->hout_list->nelts * cls->hout_list->elt_size)); for (ptrptr = (char **) cls->hout_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->hout_list->elt_size)) { /* If the specified header (*ptrptr) exists for the current request... */ if ((theitem = apr_table_get(r->headers_out, *ptrptr))) { itemsets = apr_pstrcat(r->pool, itemsets, (i > 0 ? "," : ""), "(", global_config.driver->escape(unique_id, r->pool, &global_config.db), ",", global_config.driver->escape(*ptrptr, r->pool,&global_config.db), ",", global_config.driver->escape(theitem, r->pool,&global_config.db), ")", NULL); i++; } } if ( *itemsets != '\0' ) { hout_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s", /*global_config.insertdelayed?"delayed":*/"", hout_tablename, itemsets); log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: header_out string: %s", hout_query); } /* Work through the list of headers-in defined by LogSQLWhichHeadersIn */ i = 0; itemsets = ""; ptrptr2 = (char **) (cls->hin_list->elts + (cls->hin_list->nelts * cls->hin_list->elt_size)); for (ptrptr = (char **) cls->hin_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->hin_list->elt_size)) { /* If the specified header (*ptrptr) exists for the current request... */ if ((theitem = apr_table_get(r->headers_in, *ptrptr))) { itemsets = apr_pstrcat(r->pool, itemsets, (i > 0 ? "," : ""), "(", global_config.driver->escape(unique_id, r->pool, &global_config.db), ",", global_config.driver->escape(*ptrptr, r->pool,&global_config.db), ",", global_config.driver->escape(theitem, r->pool,&global_config.db), ")", NULL); i++; } } if ( *itemsets != '\0' ) { hin_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s", /*global_config.insertdelayed?"delayed":*/"", hin_tablename, itemsets); log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: header_in string: %s", hin_query); } /* Work through the list of cookies defined by LogSQLWhichCookies */ i = 0; itemsets = ""; ptrptr2 = (char **) (cls->cookie_list->elts + (cls->cookie_list->nelts * cls->cookie_list->elt_size)); for (ptrptr = (char **) cls->cookie_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->cookie_list->elt_size)) { /* If the specified cookie (*ptrptr) exists for the current request... */ if ( strncmp((theitem = extract_specific_cookie(r, *ptrptr)), "-", 1) ) { itemsets = apr_pstrcat(r->pool, itemsets, (i > 0 ? "," : ""), "(", global_config.driver->escape(unique_id, r->pool, &global_config.db), ",", global_config.driver->escape(*ptrptr, r->pool,&global_config.db), ",", global_config.driver->escape(theitem, r->pool,&global_config.db), ")", NULL); i++; } } if ( *itemsets != '\0' ) { cookie_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s", /*global_config.insertdelayed?"delayed":*/"", cookie_tablename, itemsets); log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: cookie string: %s", cookie_query); } /* Set up the actual INSERT statement */ access_query = apr_psprintf(r->pool, "insert %s into %s (%s) values (%s)", /*global_config.insertdelayed?"delayed":*/"", transfer_tablename, fields, values); log_error(APLOG_MARK,APLOG_DEBUG,0, r->server,"mod_log_sql: access string: %s", access_query); /* If the person activated force-preserve, go ahead and push all the entries * into the preserve file, then return. */ if (global_config.forcepreserve) { log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: preservation forced"); preserve_entry(orig, access_query); if ( note_query != NULL ) preserve_entry(orig, note_query); if ( hin_query != NULL ) preserve_entry(orig, hin_query); if ( hout_query != NULL ) preserve_entry(orig, hout_query); if ( cookie_query != NULL ) preserve_entry(orig, cookie_query); return OK; } /* How's our mysql link integrity? */ if (!global_config.db.connected) { if (!global_config.forcepreserve) { /* Make a try to establish the link */ log_sql_opendb_link(r->server); } if (!global_config.db.connected) { /* Unable to re-establish a DB link, so assume that it's really * gone and send the entry to the preserve file instead. * This short-circuits safe_sql_query() during a db outage and therefore * we don't keep logging the db error over and over. */ preserve_entry(orig, access_query); if ( note_query != NULL ) preserve_entry(orig, note_query); if ( hin_query != NULL ) preserve_entry(orig, hin_query); if ( hout_query != NULL ) preserve_entry(orig, hout_query); if ( cookie_query != NULL ) preserve_entry(orig, cookie_query); return OK; } else { /* Whew, we got the DB link back */ log_error(APLOG_MARK,APLOG_NOTICE,0, orig->server,"mod_log_sql: child established database connection"); } } /* ---> So as of here we have a non-null value of mysql_log. <--- */ /* ---> i.e. we have a good MySQL connection. <--- */ /* Make the access-table insert */ safe_sql_insert(orig,LOGSQL_TABLE_ACCESS,transfer_tablename,access_query); /* Log the optional notes, headers, etc. */ if (note_query) safe_sql_insert(orig, LOGSQL_TABLE_NOTES,notes_tablename,note_query); if (hout_query) safe_sql_insert(orig, LOGSQL_TABLE_HEADERSOUT,hout_tablename,hout_query); if (hin_query) safe_sql_insert(orig, LOGSQL_TABLE_HEADERSIN,hin_tablename,hin_query); if (cookie_query) safe_sql_insert(orig, LOGSQL_TABLE_COOKIES,cookie_tablename,cookie_query); return OK; } }
static void vhost_alias_interpolate(request_rec *r, const char *name, const char *map, const char *uri) { /* 0..9 9..0 */ enum { MAXDOTS = 19 }; const char *dots[MAXDOTS+1]; int ndots; char buf[HUGE_STRING_LEN]; char *dest, last; int N, M, Np, Mp, Nd, Md; const char *start, *end; const char *p; ndots = 0; dots[ndots++] = name-1; /* slightly naughty */ for (p = name; *p; ++p){ if (*p == '.' && ndots < MAXDOTS) { dots[ndots++] = p; } } dots[ndots] = p; r->filename = NULL; dest = buf; last = '\0'; while (*map) { if (*map != '%') { /* normal characters */ vhost_alias_checkspace(r, buf, &dest, 1); last = *dest++ = *map++; continue; } /* we are in a format specifier */ ++map; /* can't be a slash */ last = '\0'; /* %% -> % */ if (*map == '%') { ++map; vhost_alias_checkspace(r, buf, &dest, 1); *dest++ = '%'; continue; } /* port number */ if (*map == 'p') { ++map; /* no. of decimal digits in a short plus one */ vhost_alias_checkspace(r, buf, &dest, 7); dest += apr_snprintf(dest, 7, "%d", ap_get_server_port(r)); continue; } /* deal with %-N+.-M+ -- syntax is already checked */ N = M = 0; /* value */ Np = Mp = 0; /* is there a plus? */ Nd = Md = 0; /* is there a dash? */ if (*map == '-') ++map, Nd = 1; N = *map++ - '0'; if (*map == '+') ++map, Np = 1; if (*map == '.') { ++map; if (*map == '-') { ++map, Md = 1; } M = *map++ - '0'; if (*map == '+') { ++map, Mp = 1; } } /* note that N and M are one-based indices, not zero-based */ start = dots[0]+1; /* ptr to the first character */ end = dots[ndots]; /* ptr to the character after the last one */ if (N != 0) { if (N > ndots) { start = "_"; end = start+1; } else if (!Nd) { start = dots[N-1]+1; if (!Np) { end = dots[N]; } } else { if (!Np) { start = dots[ndots-N]+1; } end = dots[ndots-N+1]; } } if (M != 0) { if (M > end - start) { start = "_"; end = start+1; } else if (!Md) { start = start+M-1; if (!Mp) { end = start+1; } } else { if (!Mp) { start = end-M; } end = end-M+1; } } vhost_alias_checkspace(r, buf, &dest, end - start); for (p = start; p < end; ++p) { *dest++ = apr_tolower(*p); } } *dest = '\0'; /* no double slashes */ if (last == '/') { ++uri; } if (r->filename) { r->filename = apr_pstrcat(r->pool, r->filename, buf, uri, NULL); } else { r->filename = apr_pstrcat(r->pool, buf, uri, NULL); } }
static void vhost_alias_interpolate(request_rec *r, mva_sconf_t *conf, const char *name, const char *map, const char *uri) { /* 0..9 9..0 */ enum { MAXDOTS = 19 }; const char *dots[MAXDOTS+1]; int ndots; char buf[HUGE_STRING_LEN]; char *dest; const char *docroot; int N, M, Np, Mp, Nd, Md; const char *start, *end; const char *p; ndots = 0; dots[ndots++] = name-1; /* slightly naughty */ for (p = name; *p; ++p){ if (*p == '.' && ndots < MAXDOTS) { dots[ndots++] = p; } } dots[ndots] = p; r->filename = NULL; dest = buf; while (*map) { if (*map != '%') { /* normal characters */ vhost_alias_checkspace(r, buf, &dest, 1); *dest++ = *map++; continue; } /* we are in a format specifier */ ++map; /* %% -> % */ if (*map == '%') { ++map; vhost_alias_checkspace(r, buf, &dest, 1); *dest++ = '%'; continue; } /* port number */ if (*map == 'p') { ++map; /* no. of decimal digits in a short plus one */ vhost_alias_checkspace(r, buf, &dest, 7); dest += apr_snprintf(dest, 7, "%d", ap_get_server_port(r)); continue; } /* deal with %-N+.-M+ -- syntax is already checked */ M = 0; /* value */ Np = Mp = 0; /* is there a plus? */ Nd = Md = 0; /* is there a dash? */ if (*map == '-') ++map, Nd = 1; N = *map++ - '0'; if (*map == '+') ++map, Np = 1; if (*map == '.') { ++map; if (*map == '-') { ++map, Md = 1; } M = *map++ - '0'; if (*map == '+') { ++map, Mp = 1; } } /* note that N and M are one-based indices, not zero-based */ start = dots[0]+1; /* ptr to the first character */ end = dots[ndots]; /* ptr to the character after the last one */ if (N != 0) { if (N > ndots) { start = "_"; end = start+1; } else if (!Nd) { start = dots[N-1]+1; if (!Np) { end = dots[N]; } } else { if (!Np) { start = dots[ndots-N]+1; } end = dots[ndots-N+1]; } } if (M != 0) { if (M > end - start) { start = "_"; end = start+1; } else if (!Md) { start = start+M-1; if (!Mp) { end = start+1; } } else { if (!Mp) { start = end-M; } end = end-M+1; } } vhost_alias_checkspace(r, buf, &dest, end - start); for (p = start; p < end; ++p) { *dest++ = apr_tolower(*p); } } /* no double slashes */ if (dest - buf > 0 && dest[-1] == '/') { --dest; } *dest = '\0'; /* * A this point we either have a document root which points to something * on disk - or not. * * If the document root doesn't exist on disk we can *attempt* to remap * that to the real file. * * If this remapping fails we don't care as the result will be a 404, * and that would have happened anyway. * */ { struct stat buffer; /** * If we have: * * A document root * Which doesn't exist. * * Then: * * Attempt to fix. * */ if ( ( NULL != buf ) && ( stat( buf, &buffer ) < 0 ) ) { /** * Here we strip out the first part of the name * after the /srv prefix which will result in * a request being rewritten from (for example) * * /srv/test.example.com/public/htdocs * * to: * * /srv/example.com/public/htdocs * */ update_vhost_request( buf ); } } if (r->filename) docroot = apr_pstrcat(r->pool, r->filename, buf, NULL); else docroot = apr_pstrdup(r->pool, buf); r->filename = apr_pstrcat(r->pool, docroot, uri, NULL); ap_set_context_info(r, NULL, docroot); ap_set_document_root(r, docroot); }
static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p, const char *uri, apr_uri_t *parsed_uri, const char **key) { cache_server_conf *conf; char *port_str, *hn, *lcs; const char *hostname, *scheme; int i; const char *path; char *querystring; if (*key) { /* * We have been here before during the processing of this request. */ return APR_SUCCESS; } /* * Get the module configuration. We need this for the CacheIgnoreQueryString * option below. */ conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module); /* * Use the canonical name to improve cache hit rate, but only if this is * not a proxy request or if this is a reverse proxy request. * We need to handle both cases in the same manner as for the reverse proxy * case we have the following situation: * * If a cached entry is looked up by mod_cache's quick handler r->proxyreq * is still unset in the reverse proxy case as it only gets set in the * translate name hook (either by ProxyPass or mod_rewrite) which is run * after the quick handler hook. This is different to the forward proxy * case where it gets set before the quick handler is run (in the * post_read_request hook). * If a cache entry is created by the CACHE_SAVE filter we always have * r->proxyreq set correctly. * So we must ensure that in the reverse proxy case we use the same code * path and using the canonical name seems to be the right thing to do * in the reverse proxy case. */ if (!r->proxyreq || (r->proxyreq == PROXYREQ_REVERSE)) { if (conf->base_uri && conf->base_uri->hostname) { hostname = conf->base_uri->hostname; } else { /* Use _default_ as the hostname if none present, as in mod_vhost */ hostname = ap_get_server_name(r); if (!hostname) { hostname = "_default_"; } } } else if (parsed_uri->hostname) { /* Copy the parsed uri hostname */ hn = apr_pstrdup(p, parsed_uri->hostname); ap_str_tolower(hn); /* const work-around */ hostname = hn; } else { /* We are a proxied request, with no hostname. Unlikely * to get very far - but just in case */ hostname = "_default_"; } /* * Copy the scheme, ensuring that it is lower case. If the parsed uri * contains no string or if this is not a proxy request get the http * scheme for this request. As r->parsed_uri.scheme is not set if this * is a reverse proxy request, it is ensured that the cases * "no proxy request" and "reverse proxy request" are handled in the same * manner (see above why this is needed). */ if (r->proxyreq && parsed_uri->scheme) { /* Copy the scheme and lower-case it */ lcs = apr_pstrdup(p, parsed_uri->scheme); ap_str_tolower(lcs); /* const work-around */ scheme = lcs; } else { if (conf->base_uri && conf->base_uri->scheme) { scheme = conf->base_uri->scheme; } else { scheme = ap_http_scheme(r); } } /* * If this is a proxy request, but not a reverse proxy request (see comment * above why these cases must be handled in the same manner), copy the * URI's port-string (which may be a service name). If the URI contains * no port-string, use apr-util's notion of the default port for that * scheme - if available. Otherwise use the port-number of the current * server. */ if (r->proxyreq && (r->proxyreq != PROXYREQ_REVERSE)) { if (parsed_uri->port_str) { port_str = apr_pcalloc(p, strlen(parsed_uri->port_str) + 2); port_str[0] = ':'; for (i = 0; parsed_uri->port_str[i]; i++) { port_str[i + 1] = apr_tolower(parsed_uri->port_str[i]); } } else if (apr_uri_port_of_scheme(scheme)) { port_str = apr_psprintf(p, ":%u", apr_uri_port_of_scheme(scheme)); } else { /* No port string given in the AbsoluteUri, and we have no * idea what the default port for the scheme is. Leave it * blank and live with the inefficiency of some extra cached * entities. */ port_str = ""; } } else { if (conf->base_uri && conf->base_uri->port_str) { port_str = conf->base_uri->port_str; } else if (conf->base_uri && conf->base_uri->hostname) { port_str = ""; } else { /* Use the server port */ port_str = apr_psprintf(p, ":%u", ap_get_server_port(r)); } } /* * Check if we need to ignore session identifiers in the URL and do so * if needed. */ path = uri; querystring = parsed_uri->query; if (conf->ignore_session_id->nelts) { int i; char **identifier; identifier = (char **) conf->ignore_session_id->elts; for (i = 0; i < conf->ignore_session_id->nelts; i++, identifier++) { int len; const char *param; len = strlen(*identifier); /* * Check that we have a parameter separator in the last segment * of the path and that the parameter matches our identifier */ if ((param = ap_strrchr_c(path, ';')) && !strncmp(param + 1, *identifier, len) && (*(param + len + 1) == '=') && !ap_strchr_c(param + len + 2, '/')) { path = apr_pstrndup(p, path, param - path); continue; } /* * Check if the identifier is in the querystring and cut it out. */ if (querystring) { /* * First check if the identifier is at the beginning of the * querystring and followed by a '=' */ if (!strncmp(querystring, *identifier, len) && (*(querystring + len) == '=')) { param = querystring; } else { char *complete; /* * In order to avoid subkey matching (PR 48401) prepend * identifier with a '&' and append a '=' */ complete = apr_pstrcat(p, "&", *identifier, "=", NULL); param = strstr(querystring, complete); /* If we found something we are sitting on the '&' */ if (param) { param++; } } if (param) { const char *amp; if (querystring != param) { querystring = apr_pstrndup(p, querystring, param - querystring); } else { querystring = ""; } if ((amp = ap_strchr_c(param + len + 1, '&'))) { querystring = apr_pstrcat(p, querystring, amp + 1, NULL); } else { /* * If querystring is not "", then we have the case * that the identifier parameter we removed was the * last one in the original querystring. Hence we have * a trailing '&' which needs to be removed. */ if (*querystring) { querystring[strlen(querystring) - 1] = '\0'; } } } } } } /* Key format is a URI, optionally without the query-string */ if (conf->ignorequerystring) { *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?", NULL); } else { *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?", querystring, NULL); } /* * Store the key in the request_config for the cache as r->parsed_uri * might have changed in the time from our first visit here triggered by the * quick handler and our possible second visit triggered by the CACHE_SAVE * filter (e.g. r->parsed_uri got unescaped). In this case we would save the * resource in the cache under a key where it is never found by the quick * handler during following requests. */ ap_log_rerror( APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698) "cache: Key for entity %s?%s is %s", uri, parsed_uri->query, *key); return APR_SUCCESS; }
static void cwx_tolower(char* szValue){ while(*szValue){ *szValue = apr_tolower(*szValue); szValue++; } }
svn_error_t * svn_cl__get_log_message(const char **log_msg, const char **tmp_file, const apr_array_header_t *commit_items, void *baton, apr_pool_t *pool) { svn_stringbuf_t *default_msg = NULL; struct log_msg_baton *lmb = baton; svn_stringbuf_t *message = NULL; svn_config_t *cfg; const char *mfc_after, *sponsored_by; cfg = lmb->config ? svn_hash_gets(lmb->config, SVN_CONFIG_CATEGORY_CONFIG) : NULL; /* Set default message. */ default_msg = svn_stringbuf_create(APR_EOL_STR, pool); svn_stringbuf_appendcstr(default_msg, APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "PR:\t\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Submitted by:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Reported by:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Reviewed by:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Approved by:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Obtained from:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "MFC after:\t"); svn_config_get(cfg, &mfc_after, SVN_CONFIG_SECTION_MISCELLANY, "freebsd-mfc-after", NULL); if (mfc_after != NULL) svn_stringbuf_appendcstr(default_msg, mfc_after); svn_stringbuf_appendcstr(default_msg, APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "MFH:\t\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Relnotes:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Security:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Sponsored by:\t"); svn_config_get(cfg, &sponsored_by, SVN_CONFIG_SECTION_MISCELLANY, "freebsd-sponsored-by", #ifdef HAS_ORGANIZATION_NAME ORGANIZATION_NAME); #else NULL); #endif if (sponsored_by != NULL) svn_stringbuf_appendcstr(default_msg, sponsored_by); svn_stringbuf_appendcstr(default_msg, APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "Differential Revision:\t" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX); svn_stringbuf_appendcstr(default_msg, APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Description of fields to fill in above: 76 columns --|" APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> PR: If and which Problem Report is related." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Submitted by: If someone else sent in the change." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Reported by: If someone else reported the issue." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Reviewed by: If someone else reviewed your modification." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Approved by: If you needed approval for this commit." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Obtained from: If the change is from a third party." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> MFC after: N [day[s]|week[s]|month[s]]. Request a reminder email." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> MFH: Ports tree branch name. Request approval for merge." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Relnotes: Set to 'yes' for mention in release notes." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Security: Vulnerability reference (one per line) or description." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Sponsored by: If the change was sponsored by an organization." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Differential Revision: https://reviews.freebsd.org/D### (*full* phabric URL needed)." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, "> Empty fields above will be automatically removed." APR_EOL_STR); svn_stringbuf_appendcstr(default_msg, APR_EOL_STR); *tmp_file = NULL; if (lmb->message) { svn_string_t *log_msg_str = svn_string_create(lmb->message, pool); SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, NULL, NULL, log_msg_str, lmb->message_encoding, FALSE, pool, pool), _("Error normalizing log message to internal format")); /* Strip off the EOF marker text and the junk that follows it. */ truncate_buffer_at_prefix(&(log_msg_str->len), (char *)log_msg_str->data, EDITOR_EOF_PREFIX); cleanmsg(&(log_msg_str->len), (char*)log_msg_str->data); *log_msg = log_msg_str->data; return SVN_NO_ERROR; } if (! commit_items->nelts) { *log_msg = ""; return SVN_NO_ERROR; } while (! message) { /* We still don't have a valid commit message. Use $EDITOR to get one. Note that svn_cl__edit_string_externally will still return a UTF-8'ized log message. */ int i; svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool); svn_error_t *err = SVN_NO_ERROR; svn_string_t *msg_string = svn_string_create_empty(pool); for (i = 0; i < commit_items->nelts; i++) { svn_client_commit_item3_t *item = APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *); const char *path = item->path; char text_mod = '_', prop_mod = ' ', unlock = ' '; if (! path) path = item->url; else if (lmb->base_dir) path = svn_dirent_is_child(lmb->base_dir, path, pool); /* If still no path, then just use current directory. */ if (! path || !*path) path = "."; if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) text_mod = 'R'; else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD) text_mod = 'A'; else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) text_mod = 'D'; else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS) text_mod = 'M'; if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS) prop_mod = 'M'; if (! lmb->keep_locks && item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN) unlock = 'U'; svn_stringbuf_appendbyte(tmp_message, text_mod); svn_stringbuf_appendbyte(tmp_message, prop_mod); svn_stringbuf_appendbyte(tmp_message, unlock); if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY) /* History included via copy/move. */ svn_stringbuf_appendcstr(tmp_message, "+ "); else svn_stringbuf_appendcstr(tmp_message, " "); svn_stringbuf_appendcstr(tmp_message, path); svn_stringbuf_appendcstr(tmp_message, APR_EOL_STR); } msg_string->data = tmp_message->data; msg_string->len = tmp_message->len; /* Use the external edit to get a log message. */ if (! lmb->non_interactive) { err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left, lmb->editor_cmd, lmb->base_dir ? lmb->base_dir : "", msg_string, "svn-commit", lmb->config, TRUE, lmb->message_encoding, pool); } else /* non_interactive flag says we can't pop up an editor, so error */ { return svn_error_create (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, _("Cannot invoke editor to get log message " "when non-interactive")); } /* Dup the tmpfile path into its baton's pool. */ *tmp_file = lmb->tmpfile_left = apr_pstrdup(lmb->pool, lmb->tmpfile_left); /* If the edit returned an error, handle it. */ if (err) { if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR) err = svn_error_quick_wrap (err, _("Could not use external editor to fetch log message; " "consider setting the $SVN_EDITOR environment variable " "or using the --message (-m) or --file (-F) options")); return svn_error_trace(err); } if (msg_string) message = svn_stringbuf_create_from_string(msg_string, pool); /* Strip off the EOF marker text and the junk that follows it. */ if (message) truncate_buffer_at_prefix(&message->len, message->data, EDITOR_EOF_PREFIX); /* * Since we're adding freebsd-specific tokens to the log message, * clean out any leftovers to avoid accidently sending them to other * projects that won't be expecting them. */ if (message) cleanmsg(&message->len, message->data); if (message) { /* We did get message, now check if it is anything more than just white space as we will consider white space only as empty */ apr_size_t len; for (len = 0; len < message->len; len++) { /* FIXME: should really use an UTF-8 whitespace test rather than svn_ctype_isspace, which is ASCII only */ if (! svn_ctype_isspace(message->data[len])) break; } if (len == message->len) message = NULL; } if (! message) { const char *reply; SVN_ERR(svn_cmdline_prompt_user2 (&reply, _("\nLog message unchanged or not specified\n" "(a)bort, (c)ontinue, (e)dit:\n"), NULL, pool)); if (reply) { int letter = apr_tolower(reply[0]); /* If the user chooses to abort, we cleanup the temporary file and exit the loop with a NULL message. */ if ('a' == letter) { SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool)); *tmp_file = lmb->tmpfile_left = NULL; break; } /* If the user chooses to continue, we make an empty message, which will cause us to exit the loop. We also cleanup the temporary file. */ if ('c' == letter) { SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool)); *tmp_file = lmb->tmpfile_left = NULL; message = svn_stringbuf_create_empty(pool); } /* If the user chooses anything else, the loop will continue on the NULL message. */ } } } *log_msg = message ? message->data : NULL; return SVN_NO_ERROR; }
static apr_status_t apreq_cookie_attr(apr_pool_t *p, apreq_cookie_t *c, const char *attr, apr_size_t alen, const char *val, apr_size_t vlen) { if (alen < 2) return APR_EBADARG; if ( attr[0] == '-' || attr[0] == '$' ) { ++attr; --alen; } switch (apr_tolower(*attr)) { case 'n': /* name is not an attr */ return APR_ENOTIMPL; case 'v': /* version; value is not an attr */ if (alen == 5 && strncasecmp(attr,"value", 5) == 0) return APR_ENOTIMPL; while (!apr_isdigit(*val)) { if (vlen == 0) return APREQ_ERROR_BADSEQ; ++val; --vlen; } apreq_cookie_version_set(c, *val - '0'); return APR_SUCCESS; case 'e': case 'm': /* expires, max-age */ apreq_cookie_expires(c, val); return APR_SUCCESS; case 'd': c->domain = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; case 'p': if (alen != 4) break; if (!strncasecmp("port", attr, 4)) { c->port = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } else if (!strncasecmp("path", attr, 4)) { c->path = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } break; case 'c': if (!strncasecmp("commentURL", attr, 10)) { c->commentURL = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } else if (!strncasecmp("comment", attr, 7)) { c->comment = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } break; case 's': if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen)) apreq_cookie_secure_on(c); else apreq_cookie_secure_off(c); return APR_SUCCESS; case 'h': /* httponly */ if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen)) apreq_cookie_httponly_on(c); else apreq_cookie_httponly_off(c); return APR_SUCCESS; }; return APR_ENOTIMPL; }
static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line) { char *from = NULL; char *to = NULL; char *flags = NULL; char *ourline; char delim; subst_pattern_t *nscript; int is_pattern = 0; int ignore_case = 0; int flatten = 1; ap_regex_t *r = NULL; if (apr_tolower(*line) != 's') { return "Bad Substitute format, must be an s/// pattern"; } ourline = apr_pstrdup(cmd->pool, line); delim = *++ourline; if (delim) from = ++ourline; if (from) { if (*ourline != delim) { while (*++ourline && *ourline != delim); } if (*ourline) { *ourline = '\0'; to = ++ourline; } } if (to) { if (*ourline != delim) { while (*++ourline && *ourline != delim); } if (*ourline) { *ourline = '\0'; flags = ++ourline; } } if (!delim || !from || !*from || !to) { return "Bad Substitute format, must be a complete s/// pattern"; } if (flags) { while (*flags) { delim = apr_tolower(*flags); /* re-use */ if (delim == 'i') ignore_case = 1; else if (delim == 'n') is_pattern = 1; else if (delim == 'f') flatten = 1; else if (delim == 'q') flatten = 0; else return "Bad Substitute flag, only s///[infq] are supported"; flags++; } } /* first see if we can compile the regex */ if (!is_pattern) { r = ap_pregcomp(cmd->pool, from, AP_REG_EXTENDED | (ignore_case ? AP_REG_ICASE : 0)); if (!r) return "Substitute could not compile regex"; } nscript = apr_array_push(((subst_dir_conf *) cfg)->patterns); /* init the new entries */ nscript->pattern = NULL; nscript->regexp = NULL; nscript->replacement = NULL; nscript->patlen = 0; if (is_pattern) { nscript->patlen = strlen(from); nscript->pattern = apr_strmatch_precompile(cmd->pool, from, !ignore_case); } else { nscript->regexp = r; } nscript->replacement = to; nscript->replen = strlen(to); nscript->flatten = flatten; return NULL; }
svn_error_t * svn_cl__get_log_message(const char **log_msg, const char **tmp_file, const apr_array_header_t *commit_items, void *baton, apr_pool_t *pool) { svn_stringbuf_t *default_msg = NULL; struct log_msg_baton *lmb = baton; svn_stringbuf_t *message = NULL; /* Set default message. */ default_msg = svn_stringbuf_create(APR_EOL_STR, pool); svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX); svn_stringbuf_appendcstr(default_msg, APR_EOL_STR APR_EOL_STR); *tmp_file = NULL; if (lmb->message) { svn_stringbuf_t *log_msg_buf = svn_stringbuf_create(lmb->message, pool); svn_string_t *log_msg_str = apr_pcalloc(pool, sizeof(*log_msg_str)); /* Trim incoming messages of the EOF marker text and the junk that follows it. */ truncate_buffer_at_prefix(&(log_msg_buf->len), log_msg_buf->data, EDITOR_EOF_PREFIX); /* Make a string from a stringbuf, sharing the data allocation. */ log_msg_str->data = log_msg_buf->data; log_msg_str->len = log_msg_buf->len; SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, FALSE, FALSE, log_msg_str, lmb->message_encoding, FALSE, pool, pool), _("Error normalizing log message to internal format")); *log_msg = log_msg_str->data; return SVN_NO_ERROR; } if (! commit_items->nelts) { *log_msg = ""; return SVN_NO_ERROR; } while (! message) { /* We still don't have a valid commit message. Use $EDITOR to get one. Note that svn_cl__edit_externally will still return a UTF-8'ized log message. */ int i; svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool); svn_error_t *err = SVN_NO_ERROR; svn_string_t *msg_string = svn_string_create("", pool); for (i = 0; i < commit_items->nelts; i++) { svn_client_commit_item3_t *item = APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *); const char *path = item->path; char text_mod = '_', prop_mod = ' ', unlock = ' '; if (! path) path = item->url; else if (! *path) path = "."; if (! svn_path_is_url(path) && lmb->base_dir) path = svn_dirent_is_child(lmb->base_dir, path, pool); /* If still no path, then just use current directory. */ if (! path) path = "."; if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) text_mod = 'R'; else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD) text_mod = 'A'; else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) text_mod = 'D'; else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS) text_mod = 'M'; if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS) prop_mod = 'M'; if (! lmb->keep_locks && item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN) unlock = 'U'; svn_stringbuf_appendbyte(tmp_message, text_mod); svn_stringbuf_appendbyte(tmp_message, prop_mod); svn_stringbuf_appendbyte(tmp_message, unlock); if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY) /* History included via copy/move. */ svn_stringbuf_appendcstr(tmp_message, "+ "); else svn_stringbuf_appendcstr(tmp_message, " "); svn_stringbuf_appendcstr(tmp_message, path); svn_stringbuf_appendcstr(tmp_message, APR_EOL_STR); } msg_string->data = tmp_message->data; msg_string->len = tmp_message->len; /* Use the external edit to get a log message. */ if (! lmb->non_interactive) { err = svn_cl__edit_string_externally(&msg_string, &lmb->tmpfile_left, lmb->editor_cmd, lmb->base_dir, msg_string, "svn-commit", lmb->config, TRUE, lmb->message_encoding, pool); } else /* non_interactive flag says we can't pop up an editor, so error */ { return svn_error_create (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, _("Cannot invoke editor to get log message " "when non-interactive")); } /* Dup the tmpfile path into its baton's pool. */ *tmp_file = lmb->tmpfile_left = apr_pstrdup(lmb->pool, lmb->tmpfile_left); /* If the edit returned an error, handle it. */ if (err) { if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR) err = svn_error_quick_wrap (err, _("Could not use external editor to fetch log message; " "consider setting the $SVN_EDITOR environment variable " "or using the --message (-m) or --file (-F) options")); return svn_error_trace(err); } if (msg_string) message = svn_stringbuf_create_from_string(msg_string, pool); /* Strip the prefix from the buffer. */ if (message) truncate_buffer_at_prefix(&message->len, message->data, EDITOR_EOF_PREFIX); if (message) { /* We did get message, now check if it is anything more than just white space as we will consider white space only as empty */ apr_size_t len; for (len = 0; len < message->len; len++) { /* FIXME: should really use an UTF-8 whitespace test rather than svn_ctype_isspace, which is ASCII only */ if (! svn_ctype_isspace(message->data[len])) break; } if (len == message->len) message = NULL; } if (! message) { const char *reply; SVN_ERR(svn_cmdline_prompt_user2 (&reply, _("\nLog message unchanged or not specified\n" "(a)bort, (c)ontinue, (e)dit:\n"), NULL, pool)); if (reply) { int letter = apr_tolower(reply[0]); /* If the user chooses to abort, we cleanup the temporary file and exit the loop with a NULL message. */ if ('a' == letter) { SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool)); *tmp_file = lmb->tmpfile_left = NULL; break; } /* If the user chooses to continue, we make an empty message, which will cause us to exit the loop. We also cleanup the temporary file. */ if ('c' == letter) { SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool)); *tmp_file = lmb->tmpfile_left = NULL; message = svn_stringbuf_create("", pool); } /* If the user chooses anything else, the loop will continue on the NULL message. */ } } } *log_msg = message ? message->data : NULL; return SVN_NO_ERROR; }