/* return: the strlen(string), that is, not include the '\0' */ PUBLIC int vsnprintf(char *buf, u32 size, const char *fmt, va_list args) { u32 i, offset, len; u8 c; u32 d, x; char *s, *b; char num[11]; /* 2^32 = 4294967296 + '\0' */ offset = 0; memset(buf, 0, size); memset(num, 0, sizeof(num)); len = strlen(fmt); for(i=0;i<len;i++) { if (fmt[i] == '%') { if ((i+1) == len) { /* % is the last char of the string */ buf_putc(buf, size, &offset, fmt[i]); break; } else { switch (fmt[i+1]) { case ('c'): c = va_arg(args, u32); buf_putc(buf, size, &offset, c); i++; break; case ('d'): d = va_arg(args, u32); b = itoa(num, d, 10); buf_puts(buf, size, &offset, b); i++; break; case ('x'): case ('X'): x = va_arg(args, u32); b = itoa(num, x, 16); if (fmt[i+1] == 'X') { b = &num[2]; }; buf_puts(buf, size, &offset, b); i++; break; case ('s'): s = va_arg(args, char *); b = s; if (b == NULL) { buf_puts(buf, size, &offset, "(null)"); } else { buf_puts(buf, size, &offset, b); } i++; break; default: buf_putc(buf, size, &offset, fmt[i]); /* the '%' */ break; } } } else { /* ordinary character */ buf_putc(buf, size, &offset, fmt[i]); } }
static void encode(const char *ps, int len, struct buf *buf) { const unsigned char *p = (const unsigned char *)ps; buf_reset(buf); /* allocate enough space plus a little slop to cover * escaping a few characters */ buf_ensure(buf, len+10); for ( ; len > 0 ; len--, p++) { switch (*p) { case '\0': case '\t': case '\r': case '\n': buf_putc(buf, ESCAPE); buf_putc(buf, 0x80|(*p)); break; case ESCAPE: buf_putc(buf, ESCAPE); buf_putc(buf, ESCAPE); break; default: buf_putc(buf, *p); break; } } /* ensure the buf is NUL-terminated; we pass the buf's data to * bsearch_mem(), which expects a C string, several times */ buf_cstring(buf); }
char* tnfa_toString(TNFA* tnfa){ StringBuffer* sb = buf_createDefault(); char* result; int i; IntEnumeration* ie; buf_printf(sb,"\nStart state s%d\nFinish state s%d",tnfa->start,tnfa->finish); for(i=0;i<tnfa->laststate;i++){ if(ihtab_contains(tnfa->states,i)){ TFATrans* t; buf_printf(sb,"\ns%d in: %d out: ",i,itoi_get(tnfa->inputOrder,i)); t= ihtab_get(tnfa->states, i); while(t!=NULL){ if (t->c==0) buf_printf(sb,"<s%d,'\\0',%d,%c> ",t->to,t->tag,t->priority); else buf_printf(sb,"<s%d,'%c',%d,%c> ",t->to,t->c,t->tag,t->priority); t=t->next; } } } buf_printf(sb,"\n#Tags = %d #Minimized = %d Minimized Tags ={",tnfa->tagcount,iset_size(tnfa->minimized)); ie = iset_elements(tnfa->minimized); while(ienum_hasNext(ie)){ buf_printf(sb,"%d",ienum_next(ie)); if(ienum_hasNext(ie)) buf_putc(sb,','); } buf_putc(sb,'}'); result= buf_toString(sb); buf_free(sb); return(result); }
static void decode(const char *ps, int len, struct buf *buf) { const unsigned char *p = (const unsigned char *)ps; buf_reset(buf); /* allocate enough space; we don't need slop because * decoding can only shrink the result */ buf_ensure(buf, len); for ( ; len > 0 ; len--, p++) { if (*p == ESCAPE) { if (len < 2) { /* invalid encoding, silently ignore */ continue; } len--; p++; if (*p == ESCAPE) buf_putc(buf, ESCAPE); else buf_putc(buf, (*p) & ~0x80); } else buf_putc(buf, *p); } /* Note: buf is not NUL-terminated. It happens that neither * skiplist nor berkeley backends guarantee any such thing, * and so code that depends on it is quite broken anyway */ }
void cvs_trigger_loginfo_header(BUF *buf, char *repo) { char *dir, pwd[PATH_MAX]; char hostname[HOST_NAME_MAX+1]; if (gethostname(hostname, sizeof(hostname)) == -1) { fatal("cvs_trigger_loginfo_header: gethostname failed %s", strerror(errno)); } if (getcwd(pwd, sizeof(pwd)) == NULL) fatal("cvs_trigger_loginfo_header: Cannot get working " "directory"); if ((dir = dirname(pwd)) == NULL) { fatal("cvs_trigger_loginfo_header: dirname failed %s", strerror(errno)); } buf_puts(buf, "Update of "); buf_puts(buf, current_cvsroot->cr_dir); buf_putc(buf, '/'); buf_puts(buf, repo); buf_putc(buf, '\n'); buf_puts(buf, "In directory "); buf_puts(buf, hostname); buf_puts(buf, ":"); buf_puts(buf, dir); buf_putc(buf, '/'); buf_puts(buf, repo); buf_putc(buf, '\n'); buf_putc(buf, '\n'); }
static void _card_to_tgt(const struct vparse_card *card, struct vparse_target *tgt) { const struct vparse_entry *entry; const struct vparse_card *sub; if (card->type) { _key_to_tgt("BEGIN", tgt); buf_putc(tgt->buf, ':'); _key_to_tgt(card->type, tgt); _endline(tgt); } for (entry = card->properties; entry; entry = entry->next) _entry_to_tgt(entry, tgt); for (sub = card->objects; sub; sub = sub->next) _card_to_tgt(sub, tgt); if (card->type) { _key_to_tgt("END", tgt); buf_putc(tgt->buf, ':'); _key_to_tgt(card->type, tgt); _endline(tgt); } }
/* * Format the seqset `seq' as a string. Returns a newly allocated * string which must be free()d by the caller. */ EXPORTED char *seqset_cstring(const struct seqset *seq) { struct buf buf = BUF_INITIALIZER; unsigned i; if (!seq) return NULL; if (!seq->len) return NULL; for (i = 0; i < seq->len; i++) { /* join with comma if not the first item */ if (i) buf_putc(&buf, ','); /* single value only */ if (seq->set[i].low == seq->set[i].high) format_num(&buf, seq->set[i].low); /* value range */ else { format_num(&buf, seq->set[i].low); buf_putc(&buf, ':'); format_num(&buf, seq->set[i].high); } } return buf_release(&buf); }
char *ihtab_toString(IntHashtable *p) { char *result = NULL; StringBuffer *buf = buf_createDefault(); IntEnumeration *e; int i = 0; buf_putc(buf, '{'); for(e = ihtab_getKeys(p); ienum_hasNext(e); ) { int curkey = ienum_next(e); void *curval = ihtab_get(p, curkey); if (i > 0) { buf_puts(buf, ", "); } buf_printf(buf, "%d", curkey); buf_putc(buf, '='); buf_putp(buf, curval); i++; } buf_putc(buf, '}'); result = buf_toString(buf); free(e); return result; }
static void _value_to_tgt(const char *value, struct vparse_target *tgt, int is_multival) { if (!value) return; /* null fields or array items are empty string */ for (; *value; value++) { _checkwrap(*value, tgt); switch (*value) { case '\r': break; case '\n': buf_putc(tgt->buf, '\\'); buf_putc(tgt->buf, 'n'); break; case ';': if (is_multival) break; /* or fall through */ case ',': case '\\': buf_putc(tgt->buf, '\\'); /* fall through */ default: buf_putc(tgt->buf, *value); break; } } }
static void flacdec_read_vorbis_comment(BitstreamReader *comment, unsigned channel_count, int *channel_mask) { struct bs_buffer *line = buf_new(); unsigned line_len; unsigned total_lines; const char mask_prefix[] = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK="; if (!setjmp(*br_try(comment))) { /*skip over vendor string*/ line_len = comment->read(comment, 32); comment->skip_bytes(comment, line_len); /*walk through all entries in the comment*/ for (total_lines = comment->read(comment, 32); total_lines > 0; total_lines--) { const char *s; /*populate entry one character at a time (this avoids allocating a big chunk of space if the length field is something way too large)*/ buf_reset(line); for (line_len = comment->read(comment, 32); line_len > 0; line_len--) { buf_putc( toupper((int)comment->read(comment, 8)), line); } buf_putc(0, line); /*NULL terminator*/ s = (const char *)buf_window_start(line); /*if line starts with mask prefix*/ if (strstr(s, mask_prefix) == s) { /*convert rest of line to base-16 integer*/ unsigned mask = (unsigned)strtoul( s + strlen(mask_prefix), NULL, 16); /*and populate mask field if its number of channel bits matches the stream's channel count*/ if (channel_bits(mask) == channel_count) { *channel_mask = mask; } } } br_etry(comment); } else { /*read error in VORBIS_COMMENT (probably invalid length field somewhere)*/ br_etry(comment); } buf_close(line); }
static int make_key(struct buf *buf, const struct jmapauth_token *tok) { /* Concatenate version, kind and the session id */ buf_putc(buf, tok->version); buf_putc(buf, tok->kind); buf_appendmap(buf, tok->sessionid, JMAPAUTH_SESSIONID_LEN); return 0; }
void case_buf_putc() { struct buf *buf = buf(NULL); assert(buf_putc(buf, 'a') == BUF_OK); assert(buf_putc(buf, 'b') == BUF_OK); assert(buf_putc(buf, 'c') == BUF_OK); assert(buf_putc(buf, 'd') == BUF_OK); assert(strcmp(str(buf), "abcd") == 0); buf_free(buf); }
static int _parseqstring(struct dlistsax_state *s, struct buf *buf) { buf->len = 0; /* get over the first quote */ if (*s->p++ != '"') return IMAP_INVALID_IDENTIFIER; while (s->p < s->end) { /* found the end quote */ if (*s->p == '"') { s->p++; return 0; } /* backslash just quotes the next char, no matter what it is */ if (*s->p == '\\') { s->p++; if (s->p == s->end) break; /* fall through */ } buf_putc(buf, *s->p++); } return IMAP_INVALID_IDENTIFIER; }
static void format_num(struct buf *buf, unsigned i) { if (i == UINT_MAX) buf_putc(buf, '*'); else buf_printf(buf, "%u", i); }
PRIVATE u32 buf_puts(char *buf, u32 size, u32 *offset, char *s) { u32 i; for(i=0;s[i]!='\0';i++) { buf_putc(buf, size, offset, s[i]); } return 0; }
static void _key_to_tgt(const char *key, struct vparse_target *tgt) { /* uppercase keys */ for (; *key; key++) { _checkwrap(*key, tgt); //buf_putc(tgt->buf, toupper(*key)); buf_putc(tgt->buf, *key); } }
char* unescapeStrConst(char* s){ StringBuffer *tmp = buf_createDefault(); char* r; int i, size = strlen(s); for (i = 1; i < size - 1; i++) { char c = s[i]; if(s[i]=='\\') { c = s[++i]; switch (c) { case 't': buf_puts(tmp, "\t"); break; case 'n': buf_puts(tmp, "\n"); break; case 'r': buf_puts(tmp, "\r"); break; case 'f': buf_puts(tmp, "\f"); break; case '"': buf_puts(tmp, "\""); break; case '\\': buf_puts(tmp, "\\"); break; default: buf_putc(tmp, c); break; } } else { buf_putc(tmp, c); } } r = buf_toString(tmp); buf_free (tmp); return r; }
char* plist_toString(PriorityList* p){ StringBuffer* sb=buf_createDefault(); char* result; int i; if (p==NULL) p=&defaultPList; for(i=0;i<p->length;i++){ buf_putc(sb,p->priority[i]); if(i<p->length-1) buf_puts(sb,"<-"); } result = buf_toString(sb); buf_free(sb); return result; }
char *hset_toString(HashSet *p) { char *result = NULL; StringBuffer *buf = buf_createDefault(); Enumeration *e; int i = 0; for(e = hset_elements(p); enum_hasNext(e); ) { void *curkey = (void *)enum_next(e); if (i > 0) { buf_puts(buf, ", "); } buf_putc(buf, '{'); buf_puts(buf, curkey); buf_putc(buf, '}'); i++; } result = buf_toString(buf); free(e); return result; }
static void _checkwrap(unsigned char c, struct vparse_target *tgt) { if (buf_len(tgt->buf) - tgt->last < 75) return; /* still short line */ if (c >= 0x80 && c < 0xC0) return; /* never wrap continuation chars */ /* wrap */ _endline(tgt); buf_putc(tgt->buf, ' '); }
static void import_loginfo(char *repo) { int i; char pwd[MAXPATHLEN]; if (getcwd(pwd, sizeof(pwd)) == NULL) fatal("Can't get working directory"); logbuf = buf_alloc(1024); cvs_trigger_loginfo_header(logbuf, repo); buf_puts(logbuf, "Log Message:\n"); buf_puts(logbuf, logmsg); if (logmsg[0] != '\0' && logmsg[strlen(logmsg) - 1] != '\n') buf_putc(logbuf, '\n'); buf_putc(logbuf, '\n'); buf_puts(logbuf, "Status:\n\n"); buf_puts(logbuf, "Vendor Tag:\t"); buf_puts(logbuf, vendor_tag); buf_putc(logbuf, '\n'); buf_puts(logbuf, "Release Tags:\t"); for (i = 0; i < tagcount ; i++) { buf_puts(logbuf, "\t\t"); buf_puts(logbuf, release_tags[i]); buf_putc(logbuf, '\n'); } buf_putc(logbuf, '\n'); buf_putc(logbuf, '\n'); }
char* escapeStrConst(char* s){ StringBuffer *tmp = buf_createDefault(); char* r; int i, size = strlen(s); for (i = 0; i < size; i++) { char c = s[i]; switch (c) { case '\t': buf_puts(tmp, "\\t"); break; case '\n': buf_puts(tmp, "\\n"); break; case '\r': buf_puts(tmp, "\\r"); break; case '\f': buf_puts(tmp, "\\f"); break; case '"': buf_putc(tmp, '\\'); buf_putc(tmp, c); break; case '\\': buf_puts(tmp, "\\\\"); break; default: buf_putc(tmp, c); break; } } r = buf_toString(tmp); buf_free(tmp); return r; }
void cvs_add_loginfo(char *repo) { BUF *buf; char pwd[MAXPATHLEN]; if (getcwd(pwd, sizeof(pwd)) == NULL) fatal("Can't get working directory"); buf = buf_alloc(1024); cvs_trigger_loginfo_header(buf, repo); buf_puts(buf, "Log Message:\nDirectory "); buf_puts(buf, current_cvsroot->cr_dir); buf_putc(buf, '/'); buf_puts(buf, repo); buf_puts(buf, " added to the repository\n"); buf_putc(buf, '\0'); loginfo = buf_release(buf); }
/* * Add an entry to the deny DB. Message 'msg' may be NULL, resulting * in a default message being used. Service name 'service' may be NULL, * resulting in all services being blocked for the user. The username * 'user' is a required argument. Returns an IMAP error code or 0 on * success. */ EXPORTED int denydb_set(const char *user, const char *service, const char *msg) { struct txn *txn = NULL; struct buf data = BUF_INITIALIZER; int r = 0; if (!denydb) { r = IMAP_INTERNAL; goto out; } if (!service) service = "*"; if (!user || strchr(service, '\t')) { /* the service field may not contain a TAB, it's the field separator */ r = IMAP_INVALID_IDENTIFIER; goto out; } /* compose the record */ buf_printf(&data, "%u\t", USERDENY_VERSION); buf_appendcstr(&data, service); buf_putc(&data, '\t'); buf_appendcstr(&data, (msg ? msg : default_message)); /* write the record */ do { r = cyrusdb_store(denydb, user, strlen(user), data.s, data.len, &txn); } while (r == CYRUSDB_AGAIN); if (r) { syslog(LOG_ERR, "IOERROR: couldn't store denydb record for %s: %s", user, cyrusdb_strerror(r)); r = IMAP_IOERROR; } out: if (txn) { if (r) cyrusdb_abort(denydb, txn); else cyrusdb_commit(denydb, txn); } buf_free(&data); return r; }
static void _entry_to_tgt(const struct vparse_entry *entry, struct vparse_target *tgt) { struct vparse_param *param; // rfc6350 3.3 - it is RECOMMENDED that property and parameter names be upper-case on output. if (entry->group) { _key_to_tgt(entry->group, tgt); buf_putc(tgt->buf, '.'); } _key_to_tgt(entry->name, tgt); for (param = entry->params; param; param = param->next) { buf_putc(tgt->buf, ';'); _key_to_tgt(param->name, tgt); buf_putc(tgt->buf, '='); if (_needsquote(param->value)) { /* XXX - smart quoting? */ buf_putc(tgt->buf, '"'); _paramval_to_tgt(param->value, tgt); buf_putc(tgt->buf, '"'); } else { _paramval_to_tgt(param->value, tgt); } } buf_putc(tgt->buf, ':'); if (entry->multivalue) { int i; for (i = 0; i < entry->v.values->count; i++) { if (i) buf_putc(tgt->buf, ';'); _value_to_tgt(strarray_nth(entry->v.values, i), tgt, 1); } } else { _value_to_tgt(entry->v.value, tgt, 0); } _endline(tgt); }
static void _paramval_to_tgt(const char *value, struct vparse_target *tgt) { for (; *value; value++) { _checkwrap(*value, tgt); switch (*value) { case '\r': break; case '\n': buf_putc(tgt->buf, '^'); buf_putc(tgt->buf, 'n'); break; case '^': buf_putc(tgt->buf, '^'); buf_putc(tgt->buf, '^'); break; case '"': buf_putc(tgt->buf, '^'); buf_putc(tgt->buf, '\''); break; default: buf_putc(tgt->buf, *value); } } }
/* * Construct an iCalendar property from a XML element. */ static icalproperty *xml_element_to_icalproperty(xmlNodePtr xprop) { const char *propname, *typestr; icalproperty_kind kind; icalproperty *prop = NULL; icalvalue_kind valkind; icalvalue *value; xmlNodePtr node; /* Get the property type */ propname = ucase(icalmemory_tmp_copy((const char *) xprop->name)); kind = icalenum_string_to_property_kind(propname); if (kind == ICAL_NO_PROPERTY) { syslog(LOG_WARNING, "Unknown xCal property type: %s", propname); return NULL; } /* Create new property */ prop = icalproperty_new(kind); if (!prop) { syslog(LOG_ERR, "Creation of new %s property failed", propname); return NULL; } if (kind == ICAL_X_PROPERTY) icalproperty_set_x_name(prop, propname); /* Add parameters */ node = xmlFirstElementChild(xprop); if (node && !xmlStrcmp(node->name, BAD_CAST "parameters")) { xmlNodePtr xparam; for (xparam = xmlFirstElementChild(node); xparam; xparam = xmlNextElementSibling(xparam)) { char *paramname = ucase(icalmemory_tmp_copy((const char *) xparam->name)); xmlChar *paramval = xmlNodeGetContent(xmlFirstElementChild(xparam)); /* XXX Need to handle multi-valued parameters */ icalproperty_set_parameter_from_string(prop, paramname, (const char *) paramval); xmlFree(paramval); } node = xmlNextElementSibling(node); } /* Get the value type */ if (!node) { syslog(LOG_WARNING, "Missing xCal value for %s property", propname); return NULL; } typestr = ucase(icalmemory_tmp_copy((const char *) node->name)); valkind = !strcmp(typestr, "UNKNOWN") ? ICAL_X_VALUE : icalenum_string_to_value_kind(typestr); if (valkind == ICAL_NO_VALUE) { syslog(LOG_WARNING, "Unknown xCal value type for %s property: %s", propname, typestr); return NULL; } else if (valkind == ICAL_TEXT_VALUE) { /* "text" also includes enumerated types - grab type from property */ valkind = icalproperty_kind_to_value_kind(kind); } /* Add value */ switch (kind) { case ICAL_CATEGORIES_PROPERTY: case ICAL_RESOURCES_PROPERTY: case ICAL_POLLPROPERTIES_PROPERTY: if (valkind == ICAL_TEXT_VALUE) { /* Handle multi-valued properties */ struct buf buf = BUF_INITIALIZER; xmlChar *content = NULL; content = xmlNodeGetContent(node); buf_setcstr(&buf, (const char *) content); free(content); while ((node = xmlNextElementSibling(node))) { buf_putc(&buf, ','); content = xmlNodeGetContent(node); buf_appendcstr(&buf, (const char *) content); free(content); } value = icalvalue_new_from_string(valkind, buf_cstring(&buf)); buf_free(&buf); break; } default: value = xml_element_to_icalvalue(node, valkind); if (!value) { syslog(LOG_ERR, "Parsing %s property value failed", propname); goto error; } } icalproperty_set_value(prop, value); /* Sanity check */ if ((node = xmlNextElementSibling(node))) { syslog(LOG_WARNING, "Unexpected XML element in property: %s", node->name); goto error; } return prop; error: icalproperty_free(prop); return NULL; }
static int expand_args(BUF *buf, struct file_info_list *file_info, const char *repo, const char *allowed_args, char *format) { int oldstyle, quote; struct file_info *fi = NULL; char *p, valbuf[2] = { '\0', '\0' }; const char *val; if (file_info != NULL && !TAILQ_EMPTY(file_info)) fi = TAILQ_FIRST(file_info); quote = oldstyle = 0; /* Why does GNU cvs print something if it encounters %{}? */ if (*format == '\0') oldstyle = 1; for (p = format; *p != '\0'; p++) { if (*p != '%' && strchr(allowed_args, *p) == NULL) return 1; switch (*p) { case 's': case 'V': case 'v': quote = 1; oldstyle = 1; break; default: break; } } if (quote) buf_putc(buf, '"'); if (oldstyle) { buf_puts(buf, repo); buf_putc(buf, ' '); } if (*format == '\0') return 0; /* * check like this, add only uses loginfo for directories anyway */ if (cvs_cmdop == CVS_OP_ADD) { buf_puts(buf, "- New directory"); if (quote) buf_putc(buf, '"'); return (0); } if (cvs_cmdop == CVS_OP_IMPORT) { buf_puts(buf, "- Imported sources"); if (quote) buf_putc(buf, '"'); return (0); } for (;;) { for (p = format; *p != '\0';) { val = NULL; switch (*p) { case '%': val = "%"; break; case 'b': if (fi != NULL) { valbuf[0] = fi->tag_type; val = valbuf; } break; case 'o': if (fi != NULL) val = fi->tag_op; break; case 'p': val = current_cvsroot->cr_dir; break; case 'r': val = repo; break; case 'l': case 'S': case 's': if (fi != NULL) val = fi->file_path; break; case 't': if (fi != NULL) val = fi->tag_new; break; case 'V': if (fi != NULL) { if (fi->crevstr != NULL && !strcmp(fi->crevstr, "Non-existent")) val = "NONE"; else val = fi->crevstr; } break; case 'v': if (fi != NULL) { if (fi->nrevstr != NULL && !strcmp(fi->nrevstr, "Removed")) val = "NONE"; else val = fi->nrevstr; } break; default: return 1; } if (val != NULL) buf_puts(buf, val); if (*(++p) != '\0') buf_putc(buf, ','); } if (fi != NULL) fi = TAILQ_NEXT(fi, flist); if (fi == NULL) break; if (strlen(format) == 1 && (*format == '%' || *format == 'o' || *format == 'p' || *format == 'r' || *format == 't')) break; buf_putc(buf, ' '); } if (quote) buf_putc(buf, '"'); return 0; }
static char * parse_cmd(int type, char *cmd, const char *repo, struct file_info_list *file_info) { int expanded = 0; char argbuf[2] = { '\0', '\0' }; char *allowed_args, *default_args, *args, *file, *p, *q = NULL; size_t pos; BUF *buf; switch (type) { case CVS_TRIGGER_COMMITINFO: allowed_args = "prsS{}"; default_args = " %p/%r %S"; file = CVS_PATH_COMMITINFO; break; case CVS_TRIGGER_LOGINFO: allowed_args = "prsSvVt{}"; default_args = NULL; file = CVS_PATH_LOGINFO; break; case CVS_TRIGGER_VERIFYMSG: allowed_args = "l"; default_args = " %l"; file = CVS_PATH_VERIFYMSG; break; case CVS_TRIGGER_TAGINFO: allowed_args = "btoprsSvV{}"; default_args = " %t %o %p/%r %{sv}"; file = CVS_PATH_TAGINFO; break; default: return (NULL); } /* before doing any stuff, check if the command starts with % */ for (p = cmd; *p != '%' && !isspace((unsigned char)*p) && *p != '\0'; p++) ; if (*p == '%') return (NULL); buf = buf_alloc(1024); p = cmd; again: for (; *p != '\0'; p++) { if ((pos = strcspn(p, "$%")) != 0) { buf_append(buf, p, pos); p += pos; } q = NULL; if (*p == '\0') break; if (*p++ == '$') { if (*p == '{') { pos = strcspn(++p, "}"); if (p[pos] == '\0') goto bad; } else { for (pos = 0; isalpha(p[pos]); pos++) ; if (pos == 0) { cvs_log(LP_ERR, "unrecognized variable syntax"); goto bad; } } q = xmalloc(pos + 1); memcpy(q, p, pos); q[pos] = '\0'; if (expand_var(buf, q)) goto bad; p += pos - (*(p - 1) == '{' ? 0 : 1); } else { switch (*p) { case '\0': goto bad; case '{': if (strchr(allowed_args, '{') == NULL) goto bad; pos = strcspn(++p, "}"); if (p[pos] == '\0') goto bad; q = xmalloc(pos + 1); memcpy(q, p, pos); q[pos] = '\0'; args = q; p += pos; break; default: argbuf[0] = *p; args = argbuf; break; } if (expand_args(buf, file_info, repo, allowed_args, args)) goto bad; expanded = 1; } free(q); } if (!expanded && default_args != NULL) { p = default_args; expanded = 1; goto again; } buf_putc(buf, '\0'); return (buf_release(buf)); bad: free(q); cvs_log(LP_NOTICE, "%s contains malformed command '%s'", file, cmd); buf_free(buf); return (NULL); }
/* This handles piping of the LSUB command, because we have to figure out * what mailboxes actually exist before passing them to the end user. * * It is also needed if we are doing a FIND MAILBOXES, for that we do an * LSUB on the backend anyway, because the semantics of FIND do not allow * it to return nonexistant mailboxes (RFC1176), but we need to really dumb * down the response when this is the case. */ int pipe_lsub(struct backend *s, const char *userid, const char *tag, int force_notfatal, const char *resp) { int taglen = strlen(tag); int c; int r = PROXY_OK; int exist_r; static struct buf tagb, cmd, sep, name; struct buf flags = BUF_INITIALIZER; const char *end_strip_flags[] = { " \\NonExistent)", "\\NonExistent)", " \\Noselect)", "\\Noselect)", NULL }; const char *mid_strip_flags[] = { "\\NonExistent ", "\\Noselect ", NULL }; assert(s); assert(s->timeout); s->timeout->mark = time(NULL) + IDLE_TIMEOUT; while(1) { c = getword(s->in, &tagb); if(c == EOF) { if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } if(!strncmp(tag, tagb.s, taglen)) { char buf[2048]; if(!prot_fgets(buf, sizeof(buf), s->in)) { if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* Got the end of the response */ buf_appendcstr(&s->last_result, buf); buf_cstring(&s->last_result); switch (buf[0]) { case 'O': case 'o': r = PROXY_OK; break; case 'N': case 'n': r = PROXY_NO; break; case 'B': case 'b': r = PROXY_BAD; break; default: /* huh? no result? */ if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; break; } break; /* we're done */ } c = getword(s->in, &cmd); if(c == EOF) { if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } if(strncasecmp("LSUB", cmd.s, 4) && strncasecmp("LIST", cmd.s, 4)) { prot_printf(imapd_out, "%s %s ", tagb.s, cmd.s); r = pipe_to_end_of_response(s, force_notfatal); if (r != PROXY_OK) goto out; } else { /* build up the response bit by bit */ int i; buf_reset(&flags); c = prot_getc(s->in); while(c != ')' && c != EOF) { buf_putc(&flags, c); c = prot_getc(s->in); } if(c != EOF) { /* terminate string */ buf_putc(&flags, ')'); buf_cstring(&flags); /* get the next character */ c = prot_getc(s->in); } if(c != ' ') { if(s == backend_current && !force_notfatal) fatal("Bad LSUB response from selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* Check for flags that we should remove * (e.g. Noselect, NonExistent) */ for(i=0; end_strip_flags[i]; i++) buf_replace_all(&flags, end_strip_flags[i], ")"); for (i=0; mid_strip_flags[i]; i++) buf_replace_all(&flags, mid_strip_flags[i], NULL); /* Get separator */ c = getastring(s->in, s->out, &sep); if(c != ' ') { if(s == backend_current && !force_notfatal) fatal("Bad LSUB response from selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* Get name */ c = getastring(s->in, s->out, &name); if(c == '\r') c = prot_getc(s->in); if(c != '\n') { if(s == backend_current && !force_notfatal) fatal("Bad LSUB response from selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* lookup name */ exist_r = 1; char *intname = mboxname_from_external(name.s, &imapd_namespace, userid); mbentry_t *mbentry = NULL; exist_r = mboxlist_lookup(intname, &mbentry, NULL); free(intname); if(!exist_r && (mbentry->mbtype & MBTYPE_RESERVE)) exist_r = IMAP_MAILBOX_RESERVED; mboxlist_entry_free(&mbentry); /* send our response */ /* we need to set \Noselect if it's not in our mailboxes.db */ if (resp[0] == 'L') { if(!exist_r) { prot_printf(imapd_out, "* %s %s \"%s\" ", resp, flags.s, sep.s); } else { prot_printf(imapd_out, "* %s (\\Noselect) \"%s\" ", resp, sep.s); } prot_printstring(imapd_out, name.s); prot_printf(imapd_out, "\r\n"); } else if(resp[0] == 'M' && !exist_r) { /* Note that it has to exist for a find response */ prot_printf(imapd_out, "* %s ", resp); prot_printastring(imapd_out, name.s); prot_printf(imapd_out, "\r\n"); } } } /* while(1) */ out: buf_free(&flags); return r; }