Python plugin: Folder: Add message counts as read-only properties
[claws.git] / src / plugins / python / foldertype.c
1 /* Python plugin for Claws-Mail
2  * Copyright (C) 2009 Holger Berndt
3  *
4  * This program 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 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #ifdef HAVE_CONFIG_H
19 #  include "config.h"
20 #include "claws-features.h"
21 #endif
22
23 #include <glib/gi18n.h>
24
25 #include "foldertype.h"
26 #include "folderpropertiestype.h"
27 #include "messageinfotype.h"
28 #include "mailboxtype.h"
29
30 #include <structmember.h>
31
32
33 typedef struct {
34     PyObject_HEAD
35     PyObject *properties;
36     FolderItem *folderitem;
37 } clawsmail_FolderObject;
38
39
40 static void Folder_dealloc(clawsmail_FolderObject* self)
41 {
42   Py_XDECREF(self->properties);
43   self->ob_type->tp_free((PyObject*)self);
44 }
45
46 static int Folder_init(clawsmail_FolderObject *self, PyObject *args, PyObject *kwds)
47 {
48   const char *ss = NULL;
49   FolderItem *folderitem = NULL;
50   char create = 0;
51
52   /* optional constructor argument: folderitem id string */
53   if(!PyArg_ParseTuple(args, "|sb", &ss, &create))
54     return -1;
55
56   if(ss) {
57     if(create == 0) {
58       folderitem = folder_find_item_from_identifier(ss);
59       if(!folderitem) {
60         PyErr_SetString(PyExc_ValueError, "A folder with that path does not exist, and the create parameter was False.");
61         return -1;
62       }
63     }
64     else {
65       folderitem = folder_get_item_from_identifier(ss);
66       if(!folderitem) {
67         PyErr_SetString(PyExc_IOError, "A folder with that path does not exist, and could not be created.");
68         return -1;
69       }
70     }
71   }
72
73   self->folderitem = folderitem;
74   if(folderitem)
75     self->properties = clawsmail_folderproperties_new(folderitem->prefs);
76   else {
77     Py_INCREF(Py_None);
78     self->properties = Py_None;
79   }
80
81   return 0;
82 }
83
84 static PyObject* Folder_str(clawsmail_FolderObject *self)
85 {
86   return PyString_FromFormat("Folder: %s", self->folderitem->name);
87 }
88
89 static PyObject* Folder_get_identifier(clawsmail_FolderObject *self, PyObject *args)
90 {
91   PyObject *obj;
92   gchar *id;
93   if(!self->folderitem)
94     return NULL;
95   id = folder_item_get_identifier(self->folderitem);
96   obj = Py_BuildValue("s", id);
97   g_free(id);
98   return obj;
99 }
100
101 static PyObject* Folder_get_messages(clawsmail_FolderObject *self, PyObject *args)
102 {
103   GSList *msglist, *walk;
104   PyObject *retval;
105   Py_ssize_t pos;
106
107   if(!self->folderitem)
108     return NULL;
109
110   msglist = folder_item_get_msg_list(self->folderitem);
111   retval = PyTuple_New(g_slist_length(msglist));
112   if(!retval) {
113     procmsg_msg_list_free(msglist);
114     Py_INCREF(Py_None);
115     return Py_None;
116   }
117
118   for(pos = 0, walk = msglist; walk; walk = walk->next, ++pos) {
119     PyObject *msg;
120     msg = clawsmail_messageinfo_new(walk->data);
121     PyTuple_SET_ITEM(retval, pos, msg);
122   }
123   procmsg_msg_list_free(msglist);
124
125   return retval;
126 }
127
128 static PyObject* get_name(clawsmail_FolderObject *self, void *closure)
129 {
130   if(self->folderitem && self->folderitem->name)
131     return PyString_FromString(self->folderitem->name);
132   Py_RETURN_NONE;
133 }
134
135 static PyObject* get_path(clawsmail_FolderObject *self, void *closure)
136 {
137   if(self->folderitem && self->folderitem->path)
138     return PyString_FromString(self->folderitem->path);
139   Py_RETURN_NONE;
140 }
141
142 static PyObject* get_mailbox_name(clawsmail_FolderObject *self, void *closure)
143 {
144   if(self->folderitem && self->folderitem->folder && self->folderitem->folder->name)
145     return PyString_FromString(self->folderitem->folder->name);
146   Py_RETURN_NONE;
147 }
148
149 static PyObject* get_mailbox(clawsmail_FolderObject *self, void *closure)
150 {
151   if(self->folderitem && self->folderitem->folder)
152     return clawsmail_mailbox_new(self->folderitem->folder);
153   Py_RETURN_NONE;
154 }
155
156
157 static PyObject* get_identifier(clawsmail_FolderObject *self, void *closure)
158 {
159   if(self->folderitem) {
160     gchar *id;
161     id = folder_item_get_identifier(self->folderitem);
162     if(id) {
163       PyObject *retval;
164       retval = PyString_FromString(id);
165       g_free(id);
166       return retval;
167     }
168   }
169   Py_RETURN_NONE;
170 }
171
172
173 static PyObject* get_properties(clawsmail_FolderObject *self, void *closure)
174 {
175   Py_INCREF(self->properties);
176   return self->properties;
177 }
178
179 static PyObject* get_num_messages(clawsmail_FolderObject *self, void *closure)
180 {
181   if(self && self->folderitem)
182     return PyInt_FromLong(self->folderitem->total_msgs);
183   Py_RETURN_NONE;
184 }
185
186 static PyObject* get_num_new_messages(clawsmail_FolderObject *self, void *closure)
187 {
188   if(self && self->folderitem)
189     return PyInt_FromLong(self->folderitem->new_msgs);
190   Py_RETURN_NONE;
191 }
192
193 static PyObject* get_num_unread_messages(clawsmail_FolderObject *self, void *closure)
194 {
195   if(self && self->folderitem)
196     return PyInt_FromLong(self->folderitem->unread_msgs);
197   Py_RETURN_NONE;
198 }
199
200 static PyObject* get_num_marked_messages(clawsmail_FolderObject *self, void *closure)
201 {
202   if(self && self->folderitem)
203     return PyInt_FromLong(self->folderitem->marked_msgs);
204   Py_RETURN_NONE;
205 }
206
207 static PyObject* get_num_locked_messages(clawsmail_FolderObject *self, void *closure)
208 {
209   if(self && self->folderitem)
210     return PyInt_FromLong(self->folderitem->locked_msgs);
211   Py_RETURN_NONE;
212 }
213
214 static PyObject* get_num_unread_marked_messages(clawsmail_FolderObject *self, void *closure)
215 {
216   if(self && self->folderitem)
217     return PyInt_FromLong(self->folderitem->unreadmarked_msgs);
218   Py_RETURN_NONE;
219 }
220
221 static PyObject* get_num_ignored_messages(clawsmail_FolderObject *self, void *closure)
222 {
223   if(self && self->folderitem)
224     return PyInt_FromLong(self->folderitem->ignored_msgs);
225   Py_RETURN_NONE;
226 }
227
228 static PyObject* get_num_watched_messages(clawsmail_FolderObject *self, void *closure)
229 {
230   if(self && self->folderitem)
231     return PyInt_FromLong(self->folderitem->watched_msgs);
232   Py_RETURN_NONE;
233 }
234
235 static PyObject* get_num_replied_messages(clawsmail_FolderObject *self, void *closure)
236 {
237   if(self && self->folderitem)
238     return PyInt_FromLong(self->folderitem->replied_msgs);
239   Py_RETURN_NONE;
240 }
241
242 static PyObject* get_num_forwarded_messages(clawsmail_FolderObject *self, void *closure)
243 {
244   if(self && self->folderitem)
245     return PyInt_FromLong(self->folderitem->forwarded_msgs);
246   Py_RETURN_NONE;
247 }
248
249 static PyMethodDef Folder_methods[] = {
250     {"get_identifier", (PyCFunction)Folder_get_identifier, METH_NOARGS,
251      "get_identifier() - get identifier\n"
252      "\n"
253      "Get identifier for folder as a string (e.g. #mh/foo/bar)."},
254     {"get_messages", (PyCFunction)Folder_get_messages, METH_NOARGS,
255      "get_messages() - get a tuple of messages in folder\n"
256      "\n"
257      "Get a tuple of MessageInfos for the folder.\n\n"
258      "DEPRECATED: Use identifier property instead."},
259
260      {NULL}
261 };
262
263 static PyGetSetDef Folder_getset[] = {
264     {"name", (getter)get_name, (setter)NULL,
265      "name - name of folder", NULL},
266
267     {"path", (getter)get_path, (setter)NULL,
268      "path - path of folder", NULL},
269
270     {"identifier", (getter)get_identifier, (setter)NULL,
271      "identifier - identifier of folder", NULL},
272
273     {"mailbox", (getter)get_mailbox, (setter)NULL,
274      "mailbox - corresponding mailbox", NULL},
275
276     {"mailbox_name", (getter)get_mailbox_name, (setter)NULL,
277      "mailbox_name - name of the corresponding mailbox\n\n"
278      "DEPRECATED: Use folder.mailbox.name instead", NULL},
279
280     {"properties", (getter)get_properties, (setter)NULL,
281      "properties - folder properties object", NULL},
282
283     {"num_messages", (getter)get_num_messages, (setter)NULL,
284      "num_messages - total number of messages in folder", NULL},
285
286     {"num_new_messages", (getter)get_num_new_messages, (setter)NULL,
287      "num_new_messages - number of new messages in folder", NULL},
288
289     {"num_unread_messages", (getter)get_num_unread_messages, (setter)NULL,
290      "num_unread_messages - number of unread messages in folder", NULL},
291
292     {"num_marked_messages", (getter)get_num_marked_messages, (setter)NULL,
293      "num_marked_messages - number of marked messages in folder", NULL},
294
295     {"num_locked_messages", (getter)get_num_locked_messages, (setter)NULL,
296      "num_locked_messages - number of locked messages in folder", NULL},
297
298     {"num_unread_marked_messages", (getter)get_num_unread_marked_messages, (setter)NULL,
299      "num_unread_marked_messages - number of unread marked messages in folder", NULL},
300
301     {"num_ignored_messages", (getter)get_num_ignored_messages, (setter)NULL,
302      "num_ignored_messages - number of ignored messages in folder", NULL},
303
304     {"num_watched_messages", (getter)get_num_watched_messages, (setter)NULL,
305      "num_watched_messages - number of watched messages in folder", NULL},
306
307     {"num_replied_messages", (getter)get_num_replied_messages, (setter)NULL,
308      "num_replied_messages - number of replied messages in folder", NULL},
309
310     {"num_forwarded_messages", (getter)get_num_forwarded_messages, (setter)NULL,
311      "num_forwarded_messages - number of forwarded messages in folder", NULL},
312
313     {NULL}
314 };
315
316
317 static PyTypeObject clawsmail_FolderType = {
318     PyObject_HEAD_INIT(NULL)
319     0,                         /* ob_size*/
320     "clawsmail.Folder",        /* tp_name*/
321     sizeof(clawsmail_FolderObject), /* tp_basicsize*/
322     0,                         /* tp_itemsize*/
323     (destructor)Folder_dealloc, /* tp_dealloc*/
324     0,                         /* tp_print*/
325     0,                         /* tp_getattr*/
326     0,                         /* tp_setattr*/
327     0,                         /* tp_compare*/
328     0,                         /* tp_repr*/
329     0,                         /* tp_as_number*/
330     0,                         /* tp_as_sequence*/
331     0,                         /* tp_as_mapping*/
332     0,                         /* tp_hash */
333     0,                         /* tp_call*/
334     (reprfunc)Folder_str,      /* tp_str*/
335     0,                         /* tp_getattro*/
336     0,                         /* tp_setattro*/
337     0,                         /* tp_as_buffer*/
338     Py_TPFLAGS_DEFAULT,        /* tp_flags*/
339     "Folder objects.\n\n"      /* tp_doc */
340     "The __init__ function takes two optional arguments:\n"
341     "folder = Folder(identifier, [create_if_not_existing=False])\n"
342     "The identifier is an id string (e.g. '#mh/Mail/foo/bar'),"
343     "create_if_not_existing is a boolean expression.",
344     0,                         /* tp_traverse */
345     0,                         /* tp_clear */
346     0,                         /* tp_richcompare */
347     0,                         /* tp_weaklistoffset */
348     0,                         /* tp_iter */
349     0,                         /* tp_iternext */
350     Folder_methods,            /* tp_methods */
351     0,                         /* tp_members */
352     Folder_getset,             /* tp_getset */
353     0,                         /* tp_base */
354     0,                         /* tp_dict */
355     0,                         /* tp_descr_get */
356     0,                         /* tp_descr_set */
357     0,                         /* tp_dictoffset */
358     (initproc)Folder_init,     /* tp_init */
359     0,                         /* tp_alloc */
360     0,                         /* tp_new */
361 };
362
363 gboolean cmpy_add_folder(PyObject *module)
364 {
365   clawsmail_FolderType.tp_new = PyType_GenericNew;
366   if(PyType_Ready(&clawsmail_FolderType) < 0)
367     return FALSE;
368
369   Py_INCREF(&clawsmail_FolderType);
370   return (PyModule_AddObject(module, "Folder", (PyObject*)&clawsmail_FolderType) == 0);
371 }
372
373 PyObject* clawsmail_folder_new(FolderItem *folderitem)
374 {
375   clawsmail_FolderObject *ff;
376   PyObject *arglist;
377   gchar *id;
378
379   if(!folderitem)
380     return NULL;
381
382   id = folder_item_get_identifier(folderitem);
383   if(id) {
384     arglist = Py_BuildValue("(s)", id);
385     g_free(id);
386     ff = (clawsmail_FolderObject*) PyObject_CallObject((PyObject*) &clawsmail_FolderType, arglist);
387     Py_DECREF(arglist);
388     return (PyObject*)ff;
389   }
390   Py_RETURN_NONE;
391 }
392
393 FolderItem* clawsmail_folder_get_item(PyObject *self)
394 {
395   return ((clawsmail_FolderObject*)self)->folderitem;
396 }
397
398 PyTypeObject* clawsmail_folder_get_type_object()
399 {
400   return &clawsmail_FolderType;
401 }
402
403 gboolean clawsmail_folder_check(PyObject *self)
404 {
405   return (PyObject_TypeCheck(self, &clawsmail_FolderType) != 0);
406 }