Blame view

pop3d/bulletin.c 6.6 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2
   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 4 5

   GNU Mailutils is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3, or (at your option)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   any later version.

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

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

#include "pop3d.h"

static char *bulletin_mbox_name;
static char *bulletin_db_name;

void
25
set_bulletin_db (const char *file)
26
{
27
  bulletin_db_name = strdup (file);
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
}

static void
close_bulletin_mailbox (mu_mailbox_t *pmbox)
{
  if (pmbox)
    {
      mu_mailbox_close (*pmbox);
      mu_mailbox_destroy (pmbox);
    }
}

static int
open_bulletin_mailbox (mu_mailbox_t *pmbox)
{
  int status;
  mu_mailbox_t tmbox;
  
  if ((status = mu_mailbox_create (&tmbox, bulletin_mbox_name)) != 0)
    {
      mu_error (_("Cannot create bulletin mailbox `%s': %s"),
		bulletin_mbox_name, mu_strerror (status));
      return 1;
    }

53
  if ((status = mu_mailbox_open (tmbox, MU_STREAM_READ)) != 0)
54
    {
55
      mu_mailbox_destroy (&tmbox);
56 57 58 59 60 61 62 63 64 65 66 67
      mu_error (_("Cannot open bulletin mailbox `%s': %s"),
		bulletin_mbox_name, mu_strerror (status));
      return 1;
    }
  if (!pmbox)
    close_bulletin_mailbox (&tmbox);
  else
    *pmbox = tmbox;
  return 0;
}

int
68
set_bulletin_source (const char *source)
69
{
70
  bulletin_mbox_name = strdup (source);
71
  return 0;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
}

static int
read_popbull_file (size_t *pnum)
{
  int rc = 1;
  FILE *fp;
  char *filename = mu_tilde_expansion ("~/.popbull", "/", auth_data->dir);
  
  if (!filename)
    return 1;
  fp = fopen (filename, "r");
  if (fp)
    {
      char buf[128];
      char *p = fgets (buf, sizeof buf, fp);
      if (p)
	{
	  *pnum = strtoul (buf, &p, 0);
	  rc = *p && !isspace (*p);
	}
      fclose (fp);
    }
  return rc;
}

static int
write_popbull_file (size_t num)
{
  int rc = 1;
  FILE *fp;
  char *filename = mu_tilde_expansion ("~/.popbull", "/", auth_data->dir);
  
  if (!filename)
    return 1;
  fp = fopen (filename, "w");
  if (fp)
    {
      fprintf (fp, "%s\n", mu_umaxtostr (0, num));
      fclose (fp);
      rc = 0;
    }
  return rc;
}

#ifdef USE_DBM
int
read_bulletin_db (size_t *pnum)
{
  DBM_FILE db;
  DBM_DATUM key, data;
  int rc;
  char sbuf[128];
  char *bufptr;
  char *buf = NULL;
  size_t s;
  char *p;
  
130
  rc = mu_dbm_open (bulletin_db_name, &db, MU_STREAM_READ, 0660);
131 132
  if (rc)
    {
133 134 135 136 137 138 139 140 141 142 143
      if (errno == ENOENT)
	{
	  *pnum = 0;
	  return 0;
	}
      else
	{
	  mu_error (_("Unable to open bulletin db for reading: %s"),
		    mu_strerror (errno));
	  return rc;
	}
144 145 146 147 148 149 150 151 152 153 154 155
    }

  memset (&key, 0, sizeof key);
  memset (&data, 0, sizeof data);

  MU_DATUM_PTR(key) = username;
  MU_DATUM_SIZE(key) = strlen (username);

  rc = mu_dbm_fetch (db, key, &data);

  if (rc)
    {
156 157 158 159 160 161
      int ec = errno;
      if (ec == ENOENT)
        {
           *pnum = 0;
           return 0;
        }
162
      mu_error (_("Cannot fetch bulletin db data: %s"),
163
		mu_strerror (ec));
164
      mu_dbm_close (db);
165 166
      return 1;
    }
167 168
  
  s = MU_DATUM_SIZE (data);
169 170 171 172 173 174 175 176 177 178 179 180 181
  if (s < sizeof sbuf)
    bufptr = sbuf;
  else
    {
      buf = malloc (s + 1);
      if (!buf)
	{
	  mu_error("%s", mu_strerror (errno));
	  return 1;
	}
      bufptr = buf;
    }

182
  memcpy (bufptr, MU_DATUM_PTR (data), s);
183 184
  bufptr[s] = 0;
  mu_dbm_datum_free(&data);
185 186
  mu_dbm_close (db);

187 188 189 190 191 192 193 194 195 196 197
  rc = 1;
  *pnum = strtoul (bufptr, &p, 0);
  if (*p == 0)
    rc = 0;
  else
    {
#ifdef QPOPPER_COMPAT
      if (s == sizeof long)
	{
	  long n;

198
	  n = *(long*)MU_DATUM_PTR (data);
199 200
	  if (n >= 0)
	    {
201
	      mu_diag_output (MU_DIAG_INFO,
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
		      _("assuming bulletin database is in qpopper format"));
	      *pnum = n;
	      rc = 0;
	    }
	}
      else
#endif /* QPOPPER_COMPAT */
	{
	  mu_error (_("Wrong bulletin database format for `%s'"),
		    username);
	}
    }
  
  free (buf);
  return rc;
}

int
write_bulletin_db (size_t num)
{
  DBM_FILE db;
  DBM_DATUM key, data;
  int rc;
Sergey Poznyakoff authored
225
  const char *p;
226
  
227
  rc = mu_dbm_open (bulletin_db_name, &db, MU_STREAM_RDWR, 0660);
228 229 230 231 232 233 234 235 236 237
  if (rc)
    {
      mu_error (_("Unable to open bulletin db for writing: %s"),
		mu_strerror (errno));
      return rc;
    }

  memset (&key, 0, sizeof key);
  memset (&data, 0, sizeof data);

238 239
  MU_DATUM_PTR (key) = username;
  MU_DATUM_SIZE (key) = strlen (username);
240
  p = mu_umaxtostr (0, num);
Sergey Poznyakoff authored
241
  MU_DATUM_PTR (data) = (char *) p;
242
  MU_DATUM_SIZE (data) = strlen (p);
243 244 245 246 247 248 249 250 251 252

  rc = mu_dbm_insert (db, key, data, 1);
  if (rc)
    mu_error (_("Cannot store datum in bulletin db"));

  mu_dbm_close (db);
  return rc;
}
#endif /* USE_DBM */
      
253 254
int
get_last_delivered_num (size_t *pret)
255 256
{
#ifdef USE_DBM  
257 258
  if (bulletin_db_name && read_bulletin_db (pret) == 0)
    return 0;
259
#endif
260
  return read_popbull_file (pret);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
}

void
store_last_delivered_num (size_t num)
{
#ifdef USE_DBM  
  if (bulletin_db_name && write_bulletin_db (num) == 0)
    return;
#endif
  write_popbull_file (num);
}

void
deliver_pending_bulletins ()
{
  mu_mailbox_t bull;
  int rc;
  size_t lastnum, total;

  if (!bulletin_mbox_name)
    return;
  
  rc = open_bulletin_mailbox (&bull);
284
  if (rc || get_last_delivered_num (&lastnum))
285 286
    return;

287 288 289 290
  rc = mu_mailbox_messages_count (bull, &total);
  if (rc)
    mu_error (_("Cannot count bulletins: %s"), mu_strerror (rc));
  else
291
    {
292
      mu_diag_output (MU_DIAG_DEBUG,
293 294 295 296 297 298 299
	      "user %s, last bulletin %lu, total bulletins %lu",
	      username, (unsigned long) lastnum, (unsigned long) total);
	  
      if (lastnum < total)
	{
	  size_t i;
	  size_t count = total - lastnum;
300
  
301
	  mu_diag_output (MU_DIAG_INFO,
302 303 304 305
		  ngettext ("user %s: delivering %lu pending bulletin",
			    "user %s: delivering %lu pending bulletins",
			    count),
		  username, (unsigned long) count);
306

307
	  for (i = lastnum + 1; i <= total; i++)
308
	    {
309 310 311 312 313 314 315 316 317
	      int rc;
	      mu_message_t msg;
	  
	      if ((rc = mu_mailbox_get_message (bull, i, &msg)) != 0)
		{
		  mu_error (_("Cannot read bulletin %lu: %s"),
			    (unsigned long) i, mu_strerror (rc));
		  break;
		}
318
	
319 320 321 322 323 324
	      if ((rc = mu_mailbox_append_message (mbox, msg)) != 0)
		{
		  mu_error (_("Cannot append message %lu: %s"),
			    (unsigned long) i, mu_strerror (rc));
		  break;
		}
325
	    }
326
	  store_last_delivered_num (i - 1);
327 328
	}
    }
329
    
330 331 332
  close_bulletin_mailbox (&bull);
}