Exemplo n.º 1
0
Arquivo: edit.c Projeto: jff/mathspad
/* header to be able to add this function to a menu */
void open_helpfile(void *data, int nr __attribute__((unused)))
{
    Char *c = (Char*) data;
    int i=0,hpos=0;
    Char *f;
    Char *name;
    Char *fullname;
    EDITINFO *edata;

    if (!c || !(f = (Char*) malloc(sizeof(Char)*(Ustrlen(c)+1)))) return;
    for (i=0; (f[i]=c[i]) ; i++)
	if (c[i]=='#') if (!i) hpos=-1; else if (hpos) hpos=0; else hpos=i;
    if (hpos>0) {
	name = c+hpos+1;
	f[hpos]='\0';
    } else name = c+i;
    f = standard_dir(f);
    fullname = search_through_dirs(help_dirs, nr_help_dirs, f);
    if (!fullname && f[0]=='/')
	fullname=f;
    else
	free(f);
    if (!fullname) {
	message(MP_ERROR, translate("Help document not found."));
	return;
    }
    i=0;
    while (aig(edata = (EDITINFO*) next_data_with_type(MAINEDITWINDOW, &i)) &&
	   Ustrcmp(edata->pathname,fullname))
	i++;
    if (!edata) {
	as_icon=1;
	edit_open();
	as_icon=0;
	if (state_window) {
	    edata = state_window;
	    handle_view_filename((void *) state_window, concat(fullname,NULL));
	    word_wrap_window(edata->info);
	}
    }
    if (!edata) {
	message2(MP_CLICKREMARK, translate("Unable to open an edit window for document "),
		 name);
	return;
    }
    if (name[0]) {
	int j=Ustrlen(name)+1;
	Char *cname = (Char*) malloc(j*sizeof(Char));
	if (cname) {
	    for (i=j-1;i>=0; i--) cname[i]=name[i];
	    editwindow_topto(edata->info, cname);
	    free(cname);
	}
    }
    if (edata->iconized) {
	XMapWindow(display, edata->win_id);
    }
    XRaiseWindow(display, edata->win_id);
}
Exemplo n.º 2
0
Arquivo: read.c Projeto: nigelm/xfpt
uschar *
read_paragraph(uschar *p, int *nest_info)
{
uschar *q = parabuffer;
int length = Ustrlen(p);

memcpy(q, p, length);
q += length;

*nest_info = NEST_NO;    /* Not hit .nest */

for (;;)
  {
  uschar *s;

  if ((p = read_nextline()) == NULL) break;

  if (Ustrncmp(p, ".literal ", 9) == 0)
    {
    next_line = p;
    break;
    }

  if (Ustrncmp(p, ".nest ", 6) == 0)
    {
    p += 6;
    while (isspace(*p)) p++;
    s = p + Ustrlen(p);
    while (s > p && isspace(s[-1])) s--;
    *s = 0;
    if (Ustrcmp(p, "begin") == 0) *nest_info = NEST_BEGIN;
    else if (Ustrcmp(p, "end") == 0) *nest_info = NEST_END;
    else error(26, p);
    break;
    }

  else if (*p == '.')
    {
    dot_process(p);
    continue;
    }

  /* End paragraph on encountering a completely blank line */

  for (s = p;  *s == ' ' || *s == '\t'; s++);
  if (*s == '\n') break;

  length = Ustrlen(p);
  memcpy(q, p, length);
  q += length;
  }

*q = 0;
return parabuffer;
}
Exemplo n.º 3
0
Arquivo: string.c Projeto: Exim/exim
uschar *
string_unprinting(uschar *s)
{
    uschar *p, *q, *r, *ss;
    int len, off;

    p = Ustrchr(s, '\\');
    if (!p) return s;

    len = Ustrlen(s) + 1;
    ss = store_get(len);

    q = ss;
    off = p - s;
    if (off)
    {
        memcpy(q, s, off);
        q += off;
    }

    while (*p)
    {
        if (*p == '\\')
        {
            *q++ = string_interpret_escape((const uschar **)&p);
            p++;
        }
        else
        {
            r = Ustrchr(p, '\\');
            if (!r)
            {
                off = Ustrlen(p);
                memcpy(q, p, off);
                p += off;
                q += off;
                break;
            }
            else
            {
                off = r - p;
                memcpy(q, p, off);
                q += off;
                p = r;
            }
        }
    }
    *q = '\0';

    return ss;
}
Exemplo n.º 4
0
Arquivo: mime.c Projeto: akissa/exim
static uschar *
rfc2231_to_2047(const uschar * fname, const uschar * charset, int * len)
{
int size = 0, ptr = 0;
uschar * val = string_cat(NULL, &size, &ptr, US"=?", 2);
uschar c;

if (charset)
  val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
val = string_cat(val, &size, &ptr, US"?Q?", 3);

while ((c = *fname))
  if (c == '%' && isxdigit(fname[1]) && isxdigit(fname[2]))
    {
    val = string_cat(val, &size, &ptr, US"=", 1);
    val = string_cat(val, &size, &ptr, ++fname, 2);
    fname += 2;
    }
  else
    val = string_cat(val, &size, &ptr, fname++, 1);

val = string_cat(val, &size, &ptr, US"?=", 2);
val[*len = ptr] = '\0';
return val;
}
Exemplo n.º 5
0
Arquivo: pdkim.c Projeto: ytrezq/exim
static uschar *
pdkim_decode_qp(uschar * str)
{
int nchar = 0;
uschar * q;
uschar * p = str;
uschar * n = store_get(Ustrlen(str)+1);

*n = '\0';
q = n;
while (*p)
  {
  if (*p == '=')
    {
    p = pdkim_decode_qp_char(p, &nchar);
    if (nchar >= 0)
      {
      *q++ = nchar;
      continue;
      }
    }
  else
    *q++ = *p;
  p++;
  }
*q = '\0';
return n;
}
Exemplo n.º 6
0
Arquivo: rfc2047.c Projeto: Exim/exim
static int
rfc2047_qpdecode(uschar *string, uschar **ptrptr)
{
int len = 0;
uschar *ptr;

ptr = *ptrptr = store_get(Ustrlen(string) + 1);  /* No longer than this */

while (*string != 0)
  {
  int ch = *string++;

  if (ch == '_') *ptr++ = ' ';
  else if (ch == '=')
    {
    int a = *string;
    int b = (a == 0)? 0 : string[1];
    if (!isxdigit(a) || !isxdigit(b)) return -1;  /* Bad QP string */
    *ptr++ = ((Ustrchr(hex_digits, tolower(a)) - hex_digits) << 4) +
               Ustrchr(hex_digits, tolower(b)) - hex_digits;
    string += 2;
    }
  else if (ch == ' ' || ch == '\t') return -1;    /* Whitespace is illegal */
  else *ptr++ = ch;

  len++;
  }

*ptr = 0;
return len;
}
Exemplo n.º 7
0
Arquivo: em_menu.c Projeto: Exim/exim
void create_dialog(uschar *label, uschar *value)
{
Arg warg[4];
Dimension x, y, xx, yy;
XtTranslations pop_trans;
Widget text;

/* Get the position of a reference widget so the dialog box can be put
near to it. */

get_pos_args[0].value = (XtArgVal)(&x);
get_pos_args[1].value = (XtArgVal)(&y);
XtGetValues(dialog_ref_widget, get_pos_args, 2);

/* When this is not a message_specific thing, the position of the reference
widget is relative to the window. Get the position of the top level widget and
add to the position. */

if (dialog_ref_widget != menushell)
  {
  get_pos_args[0].value = (XtArgVal)(&xx);
  get_pos_args[1].value = (XtArgVal)(&yy);
  XtGetValues(toplevel_widget, get_pos_args, 2);
  x += xx;
  y += yy;
  }

/* Create a transient shell for the dialog box. */

XtSetArg(warg[0], XtNtransientFor, queue_widget);
XtSetArg(warg[1], XtNx, x + 50);
XtSetArg(warg[2], XtNy, y + 50);
XtSetArg(warg[3], XtNallowShellResize, True);
dialog_shell = XtCreatePopupShell("forDialog", transientShellWidgetClass,
   toplevel_widget, warg, 4);

/* Create the dialog box. */

dialog_arg[0].value = (XtArgVal)label;
dialog_arg[1].value = (XtArgVal)value;
dialog_widget = XtCreateManagedWidget("dialog", dialogWidgetClass, dialog_shell,
  dialog_arg, XtNumber(dialog_arg));

/* Get the text widget from within the dialog box, give it the keyboard focus,
make it wider than the default, and override its translations to make Return
call the dialog action function. */

text = XtNameToWidget(dialog_widget, "value");
XawTextSetInsertionPoint(text, Ustrlen(value));
XtSetKeyboardFocus(dialog_widget, text);
xs_SetValues(text, 1, "width", 200);
pop_trans = XtParseTranslationTable(
  "<Key>Return:         dialogAction()\n");
XtOverrideTranslations(text, pop_trans);

/* Pop the thing up. */

XtPopup(dialog_shell, XtGrabExclusive);
XFlush(X_display);
}
Exemplo n.º 8
0
static int sqlite_callback(void *arg, int argc, char **argv, char **azColName)
{
struct strbuf *res = arg;
int i;

/* For second and subsequent results, insert \n */

if (res->string != NULL)
  res->string = string_cat(res->string, &res->size, &res->len, US"\n", 1);

if (argc > 1)
  {
  /* For multiple fields, include the field name too */
  for (i = 0; i < argc; i++)
    {
    uschar *value = US((argv[i] != NULL)? argv[i]:"<NULL>");
    res->string = lf_quote(US azColName[i], value, Ustrlen(value), res->string,
      &res->size, &res->len);
    }
  }

else
  {
  res->string = string_append(res->string, &res->size, &res->len, 1,
    (argv[0] != NULL)? argv[0]:"<NULL>");
  }

res->string[res->len] = 0;
return 0;
}
Exemplo n.º 9
0
Arquivo: tls.c Projeto: ulwanski/exim
uschar *
tls_field_from_dn(uschar * dn, const uschar * mod)
{
int insep = ',';
uschar outsep = '\n';
uschar * ele;
uschar * match = NULL;
int len;
uschar * list = NULL;

while ((ele = string_nextinlist(&mod, &insep, NULL, 0)))
  if (ele[0] != '>')
    match = ele;	/* field tag to match */
  else if (ele[1])
    outsep = ele[1];	/* nondefault output separator */

dn_to_list(dn);
insep = ',';
len = match ? Ustrlen(match) : -1;
while ((ele = string_nextinlist(CUSS &dn, &insep, NULL, 0)))
  if (  !match
     || Ustrncmp(ele, match, len) == 0 && ele[len] == '='
     )
    list = string_append_listele(list, outsep, ele+len+1);
return list;
}
Exemplo n.º 10
0
Arquivo: string.c Projeto: Exim/exim
uschar *
string_copy_dnsdomain(uschar *s)
{
    uschar *yield;
    uschar *ss = yield = store_get(Ustrlen(s) + 1);

    while (*s != 0)
    {
        if (*s != '\\')
        {
            *ss++ = *s++;
        }
        else if (isdigit(s[1]))
        {
            *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
            s += 4;
        }
        else if (*(++s) != 0)
        {
            *ss++ = *s++;
        }
    }

    *ss = 0;
    return yield;
}
Exemplo n.º 11
0
int
search_findtype(const uschar *name, int len)
{
int bot = 0;
int top = lookup_list_count;
while (top > bot)
  {
  int mid = (top + bot)/2;
  int c = Ustrncmp(name, lookup_list[mid]->name, len);

  /* If c == 0 we have matched the incoming name with the start of the search
  type name. However, some search types are substrings of others (e.g. nis and
  nisplus) so we need to check that the lengths are the same. The length of the
  type name cannot be shorter (else c would not be 0); if it is not equal it
  must be longer, and in that case, the incoming name comes before the name we
  are testing. By leaving c == 0 when the lengths are different, and doing a
  > 0 test below, this all falls out correctly. */

  if (c == 0 && Ustrlen(lookup_list[mid]->name) == len)
    {
    if (lookup_list[mid]->find != NULL) return mid;
    search_error_message  = string_sprintf("lookup type \"%.*s\" is not "
      "available (not in the binary - check buildtime LOOKUP configuration)",
      len, name);
    return -1;
    }

  if (c > 0) bot = mid + 1; else top = mid;
  }

search_error_message = string_sprintf("unknown lookup type \"%.*s\"",len,name);
return -1;
}
Exemplo n.º 12
0
static BOOL
read_nonrecipients_tree(tree_node **connect, FILE *f, uschar *buffer,
  int buffer_size)
{
tree_node *node;
int n = Ustrlen(buffer);
BOOL right = buffer[1] == 'Y';

if (n < 5) return FALSE;    /* malformed line */
buffer[n-1] = 0;            /* Remove \n */
node = store_get(sizeof(tree_node) + n - 3);
*connect = node;
Ustrcpy(node->name, buffer + 3);
node->data.ptr = NULL;

if (buffer[0] == 'Y')
  {
  if (Ufgets(buffer, buffer_size, f) == NULL ||
    !read_nonrecipients_tree(&node->left, f, buffer, buffer_size))
      return FALSE;
  }
else node->left = NULL;

if (right)
  {
  if (Ufgets(buffer, buffer_size, f) == NULL ||
    !read_nonrecipients_tree(&node->right, f, buffer, buffer_size))
      return FALSE;
  }
else node->right = NULL;

(void) count_below(*connect);
return TRUE;
}
Exemplo n.º 13
0
int
tls_import_cert(const uschar * buf, void ** cert)
{
    void * reset_point = store_get(0);
    gnutls_datum_t datum;
    gnutls_x509_crt_t crt = *(gnutls_x509_crt_t *)cert;
    int fail = 0;

    if (crt)
        gnutls_x509_crt_deinit(crt);
    else
        gnutls_global_init();

    gnutls_x509_crt_init(&crt);

    datum.data = string_unprinting(US buf);
    datum.size = Ustrlen(datum.data);
    if ((fail = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM)))
    {
        log_write(0, LOG_MAIN, "TLS error in certificate import: %s",
                  gnutls_strerror(fail));
        fail = 1;
    }
    else
        *cert = (void *)crt;

    store_reset(reset_point);
    return fail;
}
Exemplo n.º 14
0
static void
rda_write_string(int fd, uschar *s)
{
int len = (s == NULL)? 0 : Ustrlen(s) + 1;
(void)write(fd, &len, sizeof(int));
if (s != NULL) (void)write(fd, s, len);
}
Exemplo n.º 15
0
uschar *
string_localpart_alabel_to_utf8(const uschar * alabel, uschar ** err)
{
size_t p_len = Ustrlen(alabel);
punycode_uint * p;
uschar * s;
uschar * res;
int rc;

if (alabel[0] != 'x' || alabel[1] != 'n' || alabel[2] != '-' || alabel[3] != '-')
  {
  if (err) *err = US"bad alabel prefix";
  return NULL;
  }

p_len -= 4;
p = (punycode_uint *) store_get((p_len+1) * sizeof(*p));

if ((rc = punycode_decode(p_len, CCS alabel+4, &p_len, p, NULL)) != PUNYCODE_SUCCESS)
  {
  if (err) *err = US punycode_strerror(rc);
  return NULL;
  }

s = US stringprep_ucs4_to_utf8(p, p_len, NULL, &p_len);
res = string_copyn(s, p_len);
free(s);
return res;
}
Exemplo n.º 16
0
Arquivo: mime.c Projeto: akissa/exim
/* decode quoted-printable MIME part */
static ssize_t
mime_decode_qp(FILE* in, FILE* out, uschar* boundary)
{
uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH];
uschar *ipos, *opos;
ssize_t len, size = 0;

while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL)
  {
  if (boundary != NULL
     && Ustrncmp(ibuf, "--", 2) == 0
     && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0
     )
    break; /* todo: check for missing boundary */

  ipos = ibuf;
  opos = obuf;

  while (*ipos != 0)
    {
    if (*ipos == '=')
      {
      int decode_qp_result;

      ipos = mime_decode_qp_char(ipos, &decode_qp_result);

      if (decode_qp_result == -2)
	{
	/* Error from decoder. ipos is unchanged. */
	mime_set_anomaly(MIME_ANOMALY_BROKEN_QP);
	*opos = '=';
	++opos;
	++ipos;
	}
      else if (decode_qp_result == -1)
	break;
      else if (decode_qp_result >= 0)
	{
	*opos = decode_qp_result;
	++opos;
	}
      }
    else
      {
      *opos = *ipos;
      ++opos;
      ++ipos;
      }
    }
  /* something to write? */
  len = opos - obuf;
  if (len > 0)
    {
    if (fwrite(obuf, 1, len, out) != len) return -1; /* error */
    size += len;
    }
  }
return size;
}
Exemplo n.º 17
0
Arquivo: string.c Projeto: Exim/exim
uschar *
string_copy_malloc(const uschar *s)
{
    int len = Ustrlen(s) + 1;
    uschar *ss = store_malloc(len);
    memcpy(ss, s, len);
    return ss;
}
Exemplo n.º 18
0
static void
compute_cram_md5(uschar *secret, uschar *challenge, uschar *digestptr)
{
md5 base;
int i;
int len = Ustrlen(secret);
uschar isecret[64];
uschar osecret[64];
uschar md5secret[16];

/* If the secret is longer than 64 characters, we compute its MD5 digest
and use that. */

if (len > 64)
  {
  md5_start(&base);
  md5_end(&base, (uschar *)secret, len, md5secret);
  secret = (uschar *)md5secret;
  len = 16;
  }

/* The key length is now known to be <= 64. Set up the padded and xor'ed
versions. */

memcpy(isecret, secret, len);
memset(isecret+len, 0, 64-len);
memcpy(osecret, isecret, 64);

for (i = 0; i < 64; i++)
  {
  isecret[i] ^= 0x36;
  osecret[i] ^= 0x5c;
  }

/* Compute the inner MD5 digest */

md5_start(&base);
md5_mid(&base, isecret);
md5_end(&base, (uschar *)challenge, Ustrlen(challenge), md5secret);

/* Compute the outer MD5 digest */

md5_start(&base);
md5_mid(&base, osecret);
md5_end(&base, md5secret, 16, digestptr);
}
Exemplo n.º 19
0
Arquivo: tree.c Projeto: fanf2/exim
void
tree_add_duplicate(uschar *s, address_item *addr)
{
tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s));
Ustrcpy(node->name, s);
node->data.ptr = addr;
if (!tree_insertnode(&tree_duplicates, node)) store_reset(node);
}
Exemplo n.º 20
0
Arquivo: tree.c Projeto: fanf2/exim
void
tree_add_nonrecipient(uschar *s)
{
tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s));
Ustrcpy(node->name, s);
node->data.ptr = NULL;
if (!tree_insertnode(&tree_nonrecipients, node)) store_reset(node);
}
Exemplo n.º 21
0
Arquivo: string.c Projeto: Exim/exim
uschar *
string_copylc(const uschar *s)
{
    uschar *ss = store_get(Ustrlen(s) + 1);
    uschar *p = ss;
    while (*s != 0) *p++ = tolower(*s++);
    *p = 0;
    return ss;
}
Exemplo n.º 22
0
int
dbfn_delete(open_db *dbblock, uschar *key)
{
EXIM_DATUM key_datum;
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require clearing */
EXIM_DATUM_DATA(key_datum) = CS key;
EXIM_DATUM_SIZE(key_datum) = Ustrlen(key) + 1;
return EXIM_DBDEL(dbblock->dbptr, key_datum);
}
Exemplo n.º 23
0
Arquivo: rda.c Projeto: toddr/exim
static int
rda_write_string(int fd, const uschar *s)
{
int len = (s == NULL)? 0 : Ustrlen(s) + 1;
return (  write(fd, &len, sizeof(int)) != sizeof(int)
       || (s != NULL  &&  write(fd, s, len) != len)
       )
       ? -1 : 0;
}
Exemplo n.º 24
0
Arquivo: pvs.c Projeto: jff/mathspad
void pvs_add_keyword(Char *keyword, Char *step, int induct)
{
  KeywordItem *kwi;
  kwi=malloc(sizeof(KeywordItem));
  kwi->str=keyword;
  kwi->len=Ustrlen(keyword);
  kwi->step=strdup((char*)UstrtoLocale(step));
  kwi->induct=induct;
  kwi->next=kwlist;
  kwlist=kwi;
}
Exemplo n.º 25
0
void text_show(Widget w, uschar *s)
{
XawTextBlock b;
b.firstPos = 0;
b.ptr = CS s;
b.format = FMT8BIT;
b.length = Ustrlen(s);
XawTextReplace(w, text_count, text_count, &b);
text_count += b.length;
XawTextSetInsertionPoint(w, text_count);
}
Exemplo n.º 26
0
Arquivo: edit.c Projeto: jff/mathspad
void string_to_window(Char *messagegroup, Char *mess)
{
    EDITINFO *edata;
    edata=message_window(messagegroup);
    if (!edata) {
	fprintf(stderr, (char*)UstrtoLocale(translate("No window named '%s'.\n%s\n")),
		UstrtoLocale(messagegroup), UstrtoLocale(mess));
	return;
    }
    append_editwindow(edata->info, mess, Ustrlen(mess));
}
Exemplo n.º 27
0
Arquivo: edit.c Projeto: jff/mathspad
static void set_output_name(EDITINFO *einf)
{
    int i=0,l;
    if (einf->outputname) free(einf->outputname);
    i= Ustrlen(latexdir);
    l = i+Ustrlen(einf->filename)+15;
    einf->outputname = (Char*) malloc(sizeof(Char)*l);
    if (latexdir[i-1]=='/')
      concat_in(einf->outputname,latexdir,einf->filename);
    else {
      Ustrcpy(einf->outputname,latexdir);
      einf->outputname[i]='/';
      einf->outputname[i+1]=0;
      Ustrcat(einf->outputname, einf->filename);
    }
    if (output_mode==ASCII)
      Ustrncat(einf->outputname, translate(".asc"),l);
    else
      Ustrncat(einf->outputname, translate(".tex"),l);
}
Exemplo n.º 28
0
Arquivo: string.c Projeto: Exim/exim
uschar *
string_split_message(uschar *msg)
{
    uschar *s, *ss;

    if (msg == NULL || Ustrlen(msg) <= 75) return msg;
    s = ss = msg = string_copy(msg);

    for (;;)
    {
        int i = 0;
        while (i < 75 && *ss != 0 && *ss != '\n') ss++, i++;
        if (*ss == 0) break;
        if (*ss == '\n')
            s = ++ss;
        else
        {
            uschar *t = ss + 1;
            uschar *tt = NULL;
            while (--t > s + 35)
            {
                if (*t == ' ')
                {
                    if (t[-1] == ':') {
                        tt = t;
                        break;
                    }
                    if (tt == NULL) tt = t;
                }
            }

            if (tt == NULL)          /* Can't split behind - try ahead */
            {
                t = ss + 1;
                while (*t != 0)
                {
                    if (*t == ' ' || *t == '\n')
                    {
                        tt = t;
                        break;
                    }
                    t++;
                }
            }

            if (tt == NULL) break;   /* Can't find anywhere to split */
            *tt = '\n';
            s = ss = tt+1;
        }
    }

    return msg;
}
Exemplo n.º 29
0
Arquivo: tree.c Projeto: fanf2/exim
void
tree_add_unusable(host_item *h)
{
tree_node *node;
uschar s[256];
sprintf(CS s, "T:%.200s:%s", h->name, h->address);
node = store_get(sizeof(tree_node) + Ustrlen(s));
Ustrcpy(node->name, s);
node->data.val = h->why;
if (h->status == hstatus_unusable_expired) node->data.val += 256;
if (!tree_insertnode(&tree_unusable, node)) store_reset(node);
}
Exemplo n.º 30
0
Arquivo: mime.c Projeto: akissa/exim
/* just dump MIME part without any decoding */
static ssize_t
mime_decode_asis(FILE* in, FILE* out, uschar* boundary)
{
  ssize_t len, size = 0;
  uschar buffer[MIME_MAX_LINE_LENGTH];

  while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL)
    {
    if (boundary != NULL
       && Ustrncmp(buffer, "--", 2) == 0
       && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0
       )
      break;

    len = Ustrlen(buffer);
    if (fwrite(buffer, 1, (size_t)len, out) < len)
      return -1;
    size += len;
    } /* while */
  return size;
}