1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2003-2021 Free Software Foundation, Inc.
3 
4    GNU Mailutils is free software; you can redistribute it and/or modify
5    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    any later version.
8 
9    GNU Mailutils is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include <mh.h>
18 #include <mailutils/sys/msgset.h>
19 
20 static char *
private_sequence_name(const char * name)21 private_sequence_name (const char *name)
22 {
23   char *p;
24   char *mbox_dir = mh_expand_name (NULL, mh_current_folder (), NAME_ANY);
25   mu_asprintf (&p, "atr-%s-%s", name, mbox_dir);
26   free (mbox_dir);
27   return p;
28 }
29 
30 const char *
mh_seq_read(mu_mailbox_t mbox,const char * name,int flags)31 mh_seq_read (mu_mailbox_t mbox, const char *name, int flags)
32 {
33   const char *value;
34 
35   if (flags & SEQ_PRIVATE)
36     {
37       char *p = private_sequence_name (name);
38       value = mh_global_context_get (p, NULL);
39       free (p);
40     }
41   else
42     value = mh_global_sequences_get (mbox, name, NULL);
43   return value;
44 }
45 
46 static void
write_sequence(mu_mailbox_t mbox,const char * name,char * value,int private)47 write_sequence (mu_mailbox_t mbox, const char *name, char *value, int private)
48 {
49   if (value && value[0] == 0)
50     value = NULL;
51   if (private)
52     {
53       char *p = private_sequence_name (name);
54       mh_global_context_set (p, value);
55       free (p);
56     }
57   else
58     mh_global_sequences_set (mbox, name, value);
59 }
60 
61 static void
delete_sequence(mu_mailbox_t mbox,const char * name,int private)62 delete_sequence (mu_mailbox_t mbox, const char *name, int private)
63 {
64   write_sequence (mbox, name, NULL, private);
65 }
66 
67 static void
save_sequence(mu_mailbox_t mbox,const char * name,mu_msgset_t mset,int flags)68 save_sequence (mu_mailbox_t mbox, const char *name, mu_msgset_t mset,
69 	       int flags)
70 {
71   int rc;
72   mu_stream_t mstr;
73   mu_msgset_t outset;
74   mu_transport_t trans[2];
75 
76   rc = mu_msgset_translate (&outset, mset,
77 			    MU_MSGSET_UID|MU_MSGSET_IGNORE_TRANSERR);
78   if (rc)
79     {
80       mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_translate", NULL, rc);
81       exit (1);
82     }
83 
84   rc = mu_memory_stream_create (&mstr, MU_STREAM_RDWR);
85   if (rc)
86     {
87       mu_diag_funcall (MU_DIAG_ERROR, "mu_memory_stream_create", NULL, rc);
88       exit (1);
89     }
90   mu_stream_msgset_format (mstr, mu_msgset_fmt_mh, outset);
91   mu_stream_write (mstr, "", 1, NULL);
92   mu_stream_ioctl (mstr, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans);
93   write_sequence (mbox, name, (char*)trans[0], flags & SEQ_PRIVATE);
94   mu_stream_unref (mstr);
95   mu_msgset_free (outset);
96 }
97 
98 void
mh_seq_add(mu_mailbox_t mbox,const char * name,mu_msgset_t mset,int flags)99 mh_seq_add (mu_mailbox_t mbox, const char *name, mu_msgset_t mset, int flags)
100 {
101   const char *value = mh_seq_read (mbox, name, flags);
102 
103   delete_sequence (mbox, name, !(flags & SEQ_PRIVATE));
104   if (value && !(flags & SEQ_ZERO))
105     {
106       mu_msgset_t oldset;
107       mh_msgset_parse_string (&oldset, mbox, value, "cur");
108       mu_msgset_add (oldset, mset);
109       save_sequence (mbox, name, oldset, flags);
110       mu_msgset_free (oldset);
111     }
112   else
113     save_sequence (mbox, name, mset, flags);
114 }
115 
116 int
mh_seq_delete(mu_mailbox_t mbox,const char * name,mu_msgset_t mset,int flags)117 mh_seq_delete (mu_mailbox_t mbox, const char *name,
118 	       mu_msgset_t mset, int flags)
119 {
120   const char *value = mh_seq_read (mbox, name, flags);
121   mu_msgset_t oldset;
122 
123   if (!value)
124     return 0;
125   mh_msgset_parse_string (&oldset, mbox, value, "cur");
126   mu_msgset_sub (oldset, mset);
127   save_sequence (mbox, name, oldset, flags);
128   mu_msgset_free (oldset);
129   return 0;
130 }
131 
132 struct privseq_closure
133 {
134   const char *mbox_dir;
135   mu_mhprop_iterator_t fun;
136   void *data;
137   char *namebuf;
138   size_t namelen;
139 };
140 
141 static int
privseq_handler(const char * name,const char * value,void * data)142 privseq_handler (const char *name, const char *value, void *data)
143 {
144   struct privseq_closure *pclos = data;
145 
146   if (strncmp (name, "atr-", 4) == 0)
147     {
148       char *p = strchr (name + 4, '-');
149       if (p && strcmp (p + 1, pclos->mbox_dir) == 0)
150 	{
151 	  size_t len = p - name - 4;
152 	  if (pclos->namelen < len + 1)
153 	    {
154 	      pclos->namelen = len + 1;
155 	      pclos->namebuf = mu_realloc (pclos->namebuf, pclos->namelen);
156 	    }
157 	  memcpy (pclos->namebuf, name + 4, len);
158 	  pclos->namebuf[len] = 0;
159 	}
160 	return pclos->fun (pclos->namebuf, value, pclos->data);
161     }
162   return 0;
163 }
164 
165 int
mh_private_sequences_iterate(mu_mailbox_t mbox,mu_mhprop_iterator_t fp,void * data)166 mh_private_sequences_iterate (mu_mailbox_t mbox,
167 			      mu_mhprop_iterator_t fp, void *data)
168 {
169   int rc;
170   struct privseq_closure clos;
171   mu_url_t url;
172 
173   rc = mu_mailbox_get_url (mbox, &url);
174   if (rc)
175     {
176       mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_url", NULL, rc);
177       exit (1);
178     }
179   rc = mu_url_sget_path (url, &clos.mbox_dir);
180   if (rc)
181     {
182       mu_diag_funcall (MU_DIAG_ERROR, "mu_url_sget_path",
183 		       mu_url_to_string (url), rc);
184       exit (1);
185     }
186 
187   clos.fun = fp;
188   clos.data = data;
189   clos.namebuf = NULL;
190   clos.namelen = 0;
191   rc = mu_mhprop_iterate (mu_mh_context, privseq_handler, &clos);
192   free (clos.namebuf);
193   return rc;
194 }
195