Blame view

mailbox/body.c 9.02 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2 3
   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2010 Free Software
   Foundation, Inc.
4

5 6 7
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
8
   version 3 of the License, or (at your option) any later version.
9

10
   This library is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
14

15 16 17 18
   You should have received a copy of the GNU Lesser General
   Public License along with this library; if not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301 USA */
19

20 21 22
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
23 24 25 26

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
27
#include <string.h>
28
#include <unistd.h>
29 30
#include <sys/types.h>
#include <sys/stat.h>
31
#include <fcntl.h>
32

33
#include <mailutils/stream.h>
Sergey Poznyakoff authored
34
#include <mailutils/mutil.h>
35
#include <mailutils/errno.h>
36
#include <mailutils/sys/stream.h>
37 38
#include <body0.h>

39 40
#define BODY_MODIFIED 0x10000

41
static int _body_flush    (mu_stream_t);
42
static int _body_read     (mu_stream_t, char *, size_t, size_t *);
43 44
static int _body_truncate (mu_stream_t, mu_off_t);
static int _body_size     (mu_stream_t, mu_off_t *);
45 46 47 48
static int _body_write    (mu_stream_t, const char *, size_t, size_t *);
static int _body_ioctl    (mu_stream_t, int, void *);
static int _body_seek     (mu_stream_t, mu_off_t, int, mu_off_t *);
static const char *_body_error_string (mu_stream_t, int);
49 50

/* Our own defaults for the body.  */
51 52 53 54
static int _body_get_size   (mu_body_t, size_t *);
static int _body_get_lines  (mu_body_t, size_t *);
static int _body_get_size0  (mu_stream_t, size_t *);
static int _body_get_lines0 (mu_stream_t, size_t *);
55 56

int
57
mu_body_create (mu_body_t *pbody, void *owner)
58
{
59
  mu_body_t body;
60

61 62 63
  if (pbody == NULL)
    return MU_ERR_OUT_PTR_NULL;
  if (owner == NULL)
64 65 66 67 68 69 70 71 72 73 74 75
    return EINVAL;

  body = calloc (1, sizeof (*body));
  if (body == NULL)
    return ENOMEM;

  body->owner = owner;
  *pbody = body;
  return 0;
}

void
76
mu_body_destroy (mu_body_t *pbody, void *owner)
77 78 79
{
  if (pbody && *pbody)
    {
80
      mu_body_t body = *pbody;
81 82
      if (body->owner == owner)
	{
83
	  if (body->filename)
84
	    {
85
	      /* FIXME: should we do this?  */
86 87 88
	      remove (body->filename);
	      free (body->filename);
	    }
89 90

	  if (body->stream)
91
	    mu_stream_destroy (&body->stream);
92 93 94

	  if (body->fstream)
	    {
95
	      mu_stream_close (body->fstream);
96
	      mu_stream_destroy (&body->fstream);
97 98
	    }

99
	  free (body);
100 101 102 103 104
	}
      *pbody = NULL;
    }
}

105
void *
106
mu_body_get_owner (mu_body_t body)
107 108
{
  return (body) ? body->owner : NULL;
109 110 111 112
}

/* FIXME: not implemented.  */
int
113
mu_body_is_modified (mu_body_t body)
114
{
115
  return (body) ? (body->flags & BODY_MODIFIED) : 0;
116 117 118 119
}

/* FIXME: not implemented.  */
int
120
mu_body_clear_modified (mu_body_t body)
121
{
122 123
  if (body)
    body->flags &= ~BODY_MODIFIED;
124
  return 0;
125 126
}

127
int
128
mu_body_get_filename (mu_body_t body, char *filename, size_t len, size_t *pn)
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
{
  int n = 0;
  if (body == NULL)
    return EINVAL;
  if (body->filename)
    {
      n = strlen (body->filename);
      if (filename && len > 0)
	{
	  len--; /* Space for the null.  */
	  strncpy (filename, body->filename, len)[len] = '\0';
	}
    }
  if (pn)
    *pn = n;
  return 0;
}

147 148 149 150 151 152 153 154 155

struct _mu_body_stream
{
  struct _mu_stream stream;
  mu_body_t body;
};

static int
_body_get_stream (mu_body_t body, mu_stream_t *pstream, int ref)
156
{
157
  if (body == NULL)
158
    return EINVAL;
159 160
  if (pstream == NULL)
    return MU_ERR_OUT_PTR_NULL;
161 162 163

  if (body->stream == NULL)
    {
164 165 166 167 168 169 170 171
      int status;
      struct _mu_body_stream *str =
	(struct _mu_body_stream *)
	   _mu_stream_create (sizeof (*str),
			      MU_STREAM_RDWR|MU_STREAM_SEEK);
      if (!str)
	return ENOMEM;
      
172
      /* Create the temporary file.  */
173
      body->filename = mu_tempname (NULL);
174
      status = mu_file_stream_create (&body->fstream, 
175
				      body->filename, MU_STREAM_RDWR);
176 177
      if (status != 0)
	return status;
178
      status = mu_stream_open (body->fstream);
179 180
      if (status != 0)
	return status;
181 182 183 184 185 186 187 188 189
      str->stream.ctl = _body_ioctl;
      str->stream.read = _body_read;
      str->stream.write = _body_write;
      str->stream.truncate = _body_truncate;
      str->stream.size = _body_size;
      str->stream.seek = _body_seek;
      str->stream.flush = _body_flush;
      str->body = body;
      body->stream = (mu_stream_t) str;
190 191 192
      /* Override the defaults.  */
      body->_lines = _body_get_lines;
      body->_size = _body_get_size;
193
    }
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
  if (!ref)
    {
      *pstream = body->stream;
      return 0;
    }
  return mu_streamref_create (pstream, body->stream);
}

int
mu_body_get_stream (mu_body_t body, mu_stream_t *pstream)
{
  /* FIXME: Deprecation warning */
  return _body_get_stream (body, pstream, 0);
}

int
mu_body_get_streamref (mu_body_t body, mu_stream_t *pstream)
{
  return _body_get_stream (body, pstream, 1);
213 214 215
}

int
216
mu_body_set_stream (mu_body_t body, mu_stream_t stream, void *owner)
217 218 219 220 221
{
  if (body == NULL)
   return EINVAL;
  if (body->owner != owner)
    return EACCES;
222 223
  /* make sure we destroy the old one if it is owned by the body */
  mu_stream_destroy (&body->stream);
224
  body->stream = stream;
225
  body->flags |= BODY_MODIFIED;
226 227 228 229
  return 0;
}

int
230
mu_body_set_lines (mu_body_t body, int (*_lines) (mu_body_t, size_t *), void *owner)
231 232 233
{
  if (body == NULL)
    return EINVAL;
234
  if (body->owner != owner)
235 236 237 238 239 240
    return EACCES;
  body->_lines = _lines;
  return 0;
}

int
241
mu_body_lines (mu_body_t body, size_t *plines)
242 243 244 245 246
{
  if (body == NULL)
    return EINVAL;
  if (body->_lines)
    return body->_lines (body, plines);
247 248 249
  /* Fall on the stream.  */
  if (body->stream)
    return _body_get_lines0 (body->stream, plines);
250 251 252 253 254 255
  if (plines)
    *plines = 0;
  return 0;
}

int
256
mu_body_size (mu_body_t body, size_t *psize)
257 258 259 260 261
{
  if (body == NULL)
    return EINVAL;
  if (body->_size)
    return body->_size (body, psize);
262 263 264
  /* Fall on the stream.  */
  if (body->stream)
    return _body_get_size0 (body->stream, psize);
265
  if (psize)
266
    *psize = 0;
267
  return 0;
268 269 270
}

int
271
mu_body_set_size (mu_body_t body, int (*_size)(mu_body_t, size_t*) , void *owner)
272 273 274 275 276 277 278 279 280
{
  if (body == NULL)
    return EINVAL;
  if (body->owner != owner)
    return EACCES;
  body->_size = _size;
  return 0;
}

281 282
/* Stub function for the body stream.  */

283
static int
284 285 286 287
_body_seek (mu_stream_t stream, mu_off_t off, int whence, mu_off_t *presult)
{
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
288
  return mu_stream_seek (body->fstream, off, whence, presult);
289 290 291 292
}

static const char *
_body_error_string (mu_stream_t stream, int rc)
293
{
294 295
  /* FIXME: How to know if rc was returned by a body->stream? */
  return NULL;
296 297 298
}

static int
299
_body_ioctl (mu_stream_t stream, int code, void *ptr)
300
{
301 302 303
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
  return mu_stream_ioctl (body->fstream, code, ptr);
304 305 306
}

static int
307
_body_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
308
{
309 310 311
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
  return mu_stream_read (body->fstream, buf, size, pret);
312 313 314
}

static int
315
_body_write (mu_stream_t stream, const char *buf, size_t size, size_t *pret)
316
{
317 318 319
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
  return mu_stream_write (body->fstream, buf, size, pret);
320 321 322
}

static int
323
_body_truncate (mu_stream_t stream, mu_off_t n)
324
{
325 326
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
327
  return mu_stream_truncate (body->fstream, n);
328 329 330
}

static int
331
_body_size (mu_stream_t stream, mu_off_t *size)
332
{
333 334
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
335
  return mu_stream_size (body->fstream, size);
336 337 338
}

static int
339
_body_flush (mu_stream_t stream)
340
{
341 342
  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
  mu_body_t body = str->body;
343
  return mu_stream_flush (body->fstream);
344 345
}

346
/* Default function for the body.  */
347
static int
348
_body_get_lines (mu_body_t body, size_t *plines)
349 350 351 352 353
{
  return _body_get_lines0 (body->fstream, plines);
}

static int
354
_body_get_size (mu_body_t body, size_t *psize)
355 356 357 358 359
{
  return _body_get_size0 (body->fstream, psize);
}

static int
360
_body_get_size0 (mu_stream_t stream, size_t *psize)
361
{
362
  mu_off_t off = 0;
363
  int status = mu_stream_size (stream, &off);
364 365
  if (psize)
    *psize = off;
366 367 368 369
  return status;
}

static int
370
_body_get_lines0 (mu_stream_t stream, size_t *plines)
371
{
372
  int status =  mu_stream_flush (stream);
373
  size_t lines = 0;
374
  
375 376 377 378
  if (status == 0)
    {
      char buf[128];
      size_t n = 0;
379 380 381 382

      status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
      if (status)
	return status;
383
      while ((status = mu_stream_readline (stream, buf, sizeof buf,
384
					   &n)) == 0 && n > 0)
385 386 387 388 389 390 391 392 393 394
	{
	  if (buf[n - 1] == '\n')
	    lines++;
	}
    }
  if (plines)
    *plines = lines;
  return status;
}

395