Blame view

imap4d/sync.c 5.32 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2 3
   Copyright (C) 1999, 2001, 2005, 2007, 2009, 2010 Free Software
   Foundation, Inc.
4

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

10
   GNU Mailutils is distributed in the hope that it will be useful,
11 12 13 14 15
   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
16
   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
17 18

#include "imap4d.h"
19
#include <mailutils/observer.h>
20 21 22 23

/*

 */
24 25 26
static int *attr_table;
static size_t attr_table_count;
static int attr_table_loaded;
27 28 29 30

static void
free_uids (void)
{
31
  if (attr_table)
32
    {
33 34
      free (attr_table);
      attr_table = NULL;
35
    }
36 37
  attr_table_count = 0;
  attr_table_loaded = 0;
38 39 40
}

static void
41
reread_attributes (void)
42 43 44 45 46 47
{
  size_t total = 0;
  size_t i;

  free_uids ();

48
  mu_mailbox_messages_count (mbox, &total);
49 50 51 52 53 54 55 56
  if (total > attr_table_count)
    {
      attr_table = realloc (attr_table, sizeof (*attr_table) * total);
      if (!attr_table)
	imap4d_bye (ERR_NO_MEM);
      attr_table_count = total;
    }
  
57 58
  for (i = 1; i <= total; i++)
    {
59 60
      mu_message_t msg = NULL;
      mu_attribute_t attr = NULL;
61

62
      mu_mailbox_get_message (mbox, i, &msg);
63
      mu_message_get_attribute (msg, &attr);
64
      mu_attribute_get_flags (attr, &attr_table[i-1]);
65
    }
66
  attr_table_loaded = 1;
67 68
}

69 70 71 72 73
static void
notify (void)
{
  size_t total = 0;
  int reset = 0;
74
  size_t recent = 0;
75
  
76
  mu_mailbox_messages_count (mbox, &total);
77

78
  if (!attr_table)
79 80
    {
      reset = 1;
81 82
      reread_attributes ();
      mu_mailbox_messages_recent (mbox, &recent);
83
    }
84
  else if (attr_table)
85 86 87 88 89
    {
      size_t i;

      for (i = 1; i <= total; i++)
	{
90
	  mu_message_t msg = NULL;
91 92 93
	  mu_attribute_t nattr = NULL;
	  int nflags;
	  
94
	  mu_mailbox_get_message (mbox, i, &msg);
95 96 97 98 99 100 101 102 103 104
	  mu_message_get_attribute (msg, &nattr);
	  mu_attribute_get_flags (nattr, &nflags);

	  if (nflags != attr_table[i-1])
	    {
	      io_sendf ("* %lu FETCH FLAGS (",  (unsigned long) i);
	      util_format_attribute_flags (iostream, nflags);
	      io_sendf (")\n");
	      attr_table[i-1] = nflags;
	    }
105
	}
106
      mu_mailbox_messages_recent (mbox, &recent);
107 108
    }

109 110
  io_untagged_response (RESP_NONE, "%lu EXISTS", (unsigned long) total);
  io_untagged_response (RESP_NONE, "%lu RECENT", (unsigned long) recent);
111

112
  if (!reset)
113
    reread_attributes ();
114 115
}

116 117 118
size_t
uid_to_msgno (size_t uid)
{
119 120 121
  size_t msgno;
  mu_mailbox_translate (mbox, MU_MAILBOX_UID_TO_MSGNO, uid, &msgno);
  return msgno;
122 123 124 125 126
}

int
imap4d_sync_flags (size_t msgno)
{
127 128 129 130 131 132 133 134
  if (attr_table)
    {
      mu_message_t msg = NULL;
      mu_attribute_t attr = NULL;
      mu_mailbox_get_message (mbox, msgno, &msg);
      mu_message_get_attribute (msg, &attr);
      mu_attribute_get_flags (attr, &attr_table[msgno-1]);
    }
135 136 137
  return 0;
}

138 139 140
static int mailbox_corrupt;

static int
141
action (mu_observer_t observer, size_t type, void *data, void *action_data)
142 143 144 145 146 147 148 149 150 151
{
  switch (type)
    {
    case MU_EVT_MAILBOX_CORRUPT:
      mailbox_corrupt = 1;
      break;

    case MU_EVT_MAILBOX_DESTROY:
      mailbox_corrupt = 0;
      break;
152 153 154 155 156 157 158 159 160 161 162 163 164

    case MU_EVT_MAILBOX_MESSAGE_EXPUNGE:
      /* The EXPUNGE response reports that the specified message sequence
	 number has been permanently removed from the mailbox.  The message
	 sequence number for each successive message in the mailbox is
	 immediately decremented by 1, and this decrement is reflected in
	 message sequence numbers in subsequent responses (including other
	 untagged EXPUNGE responses). */
      {
	size_t *exp = data;
	io_untagged_response (RESP_NONE, "%lu EXPUNGED",
			      (unsigned long) (exp[0] - exp[1]));
      }
165 166 167 168 169
    }
  return 0;
}

void
170
imap4d_set_observer (mu_mailbox_t mbox)
171
{
172 173
  mu_observer_t observer;
  mu_observable_t observable;
174
      
175 176
  mu_observer_create (&observer, mbox);
  mu_observer_set_action (observer, action, mbox);
177
  mu_mailbox_get_observable (mbox, &observable);
178 179 180 181 182
  mu_observable_attach (observable,
			MU_EVT_MAILBOX_CORRUPT|
			MU_EVT_MAILBOX_DESTROY|
			MU_EVT_MAILBOX_MESSAGE_EXPUNGE,
			observer);
183 184 185
  mailbox_corrupt = 0;
}

186 187 188
int
imap4d_sync (void)
{
189
  /* If mbox --> NULL, it means to free all the resources.
190 191
     It may be because of close or before select/examine a new mailbox.
     If it was a close we do not send any notification.  */
192 193
  if (mbox == NULL)
    free_uids ();
194
  else if (!attr_table_loaded || !mu_mailbox_is_updated (mbox))
195 196 197 198 199
    {
      if (mailbox_corrupt)
	{
	  /* Some messages have been deleted from the mailbox by some other
	     party */
200
	  int status = mu_mailbox_close (mbox);
201 202
	  if (status)
	    imap4d_bye (ERR_MAILBOX_CORRUPTED);
203
	  status = mu_mailbox_open (mbox, MU_STREAM_RDWR);
204 205 206 207 208
	  if (status)
	    imap4d_bye (ERR_MAILBOX_CORRUPTED);
	  imap4d_set_observer (mbox);
	  free_uids ();
	  mailbox_corrupt = 0;
209 210
	  io_untagged_response (RESP_NONE,
		             "OK [ALERT] Mailbox modified by another program");
211 212 213
	}
      notify ();
    }
214 215 216
  else
    {
      size_t count = 0;
217
      mu_mailbox_messages_count (mbox, &count);
218
      if (count != attr_table_count)
219
	notify ();
220
    }
221 222
  return 0;
}