1 /* Python plugin for Claws-Mail
2 * Copyright (C) 2009-2014 Holger Berndt
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.
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.
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/>.
20 #include "claws-features.h"
23 #include "messageinfotype.h"
25 #include "common/tags.h"
26 #include "common/defs.h"
27 #include "mainwindow.h"
28 #include "summaryview.h"
29 #include "procheader.h"
31 #include <glib/gi18n.h>
33 #include <structmember.h>
37 #define HEADER_CONTENT_SIZE BUFFSIZE
42 } clawsmail_MessageInfoObject;
45 static void MessageInfo_dealloc(clawsmail_MessageInfoObject* self)
47 self->ob_type->tp_free((PyObject*)self);
50 static int MessageInfo_init(clawsmail_MessageInfoObject *self, PyObject *args, PyObject *kwds)
55 static PyObject* MessageInfo_str(clawsmail_MessageInfoObject *self)
60 From = self->msginfo->from ? self->msginfo->from : "";
61 Subject = self->msginfo->subject ? self->msginfo->subject : "";
62 return PyString_FromFormat("MessageInfo: %s / %s", From, Subject);
67 static PyObject *py_boolean_return_value(gboolean val)
79 static PyObject *is_new(PyObject *self, PyObject *args)
81 return py_boolean_return_value(MSG_IS_NEW(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
84 static PyObject *is_unread(PyObject *self, PyObject *args)
86 return py_boolean_return_value(MSG_IS_UNREAD(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
89 static PyObject *is_marked(PyObject *self, PyObject *args)
91 return py_boolean_return_value(MSG_IS_MARKED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
94 static PyObject *is_replied(PyObject *self, PyObject *args)
96 return py_boolean_return_value(MSG_IS_REPLIED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
99 static PyObject *is_locked(PyObject *self, PyObject *args)
101 return py_boolean_return_value(MSG_IS_LOCKED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
104 static PyObject *is_forwarded(PyObject *self, PyObject *args)
106 return py_boolean_return_value(MSG_IS_FORWARDED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
109 static PyObject* get_tags(PyObject *self, PyObject *args)
113 PyObject *tags_tuple;
115 tags_list = ((clawsmail_MessageInfoObject*)self)->msginfo->tags;
116 num_tags = g_slist_length(tags_list);
118 tags_tuple = PyTuple_New(num_tags);
119 if(tags_tuple != NULL) {
121 PyObject *tag_object;
125 for(walk = tags_list; walk; walk = walk->next) {
126 tag_object = Py_BuildValue("s", tags_get_tag(GPOINTER_TO_INT(walk->data)));
127 if(tag_object == NULL) {
128 Py_DECREF(tags_tuple);
131 PyTuple_SET_ITEM(tags_tuple, iTag++, tag_object);
139 static PyObject* add_or_remove_tag(PyObject *self, PyObject *args, gboolean add)
147 retval = PyArg_ParseTuple(args, "s", &tag_str);
151 tag_id = tags_get_id_for_str(tag_str);
153 PyErr_SetString(PyExc_ValueError, "Tag does not exist");
157 msginfo = ((clawsmail_MessageInfoObject*)self)->msginfo;
160 /* raise KeyError if tag is not set */
161 if(!g_slist_find(msginfo->tags, GINT_TO_POINTER(tag_id))) {
162 PyErr_SetString(PyExc_KeyError, "Tag is not set on this message");
167 procmsg_msginfo_update_tags(msginfo, add, tag_id);
170 mainwin = mainwindow_get_mainwindow();
172 summary_redisplay_msg(mainwin->summaryview);
179 static PyObject* add_tag(PyObject *self, PyObject *args)
181 return add_or_remove_tag(self, args, TRUE);
185 static PyObject* remove_tag(PyObject *self, PyObject *args)
187 return add_or_remove_tag(self, args, FALSE);
190 static PyObject* get_header(PyObject *self, PyObject *args)
194 char *header_str_dup;
196 gchar header_content[HEADER_CONTENT_SIZE];
198 retval = PyArg_ParseTuple(args, "s", &header_str);
202 msginfo = ((clawsmail_MessageInfoObject*)self)->msginfo;
204 header_str_dup = g_strdup(header_str);
205 retval = procheader_get_header_from_msginfo(msginfo, header_content, HEADER_CONTENT_SIZE, header_str);
206 g_free(header_str_dup);
208 PyObject *header_content_object;
209 gchar *content_start;
211 /* the string is now Header: Value. Strip the Header: part */
212 content_start = strstr(header_content, ":");
213 if(content_start == NULL)
214 content_start = header_content;
217 /* strip leading spaces */
218 while(*content_start == ' ')
220 header_content_object = Py_BuildValue("s", content_start);
221 return header_content_object;
228 static PyObject* get_From(clawsmail_MessageInfoObject *self, void *closure)
230 if(self->msginfo && self->msginfo->from)
231 return PyString_FromString(self->msginfo->from);
235 static PyObject* get_To(clawsmail_MessageInfoObject *self, void *closure)
237 if(self->msginfo && self->msginfo->to)
238 return PyString_FromString(self->msginfo->to);
242 static PyObject* get_Cc(clawsmail_MessageInfoObject *self, void *closure)
244 if(self->msginfo && self->msginfo->cc)
245 return PyString_FromString(self->msginfo->cc);
249 static PyObject* get_Subject(clawsmail_MessageInfoObject *self, void *closure)
251 if(self->msginfo && self->msginfo->subject)
252 return PyString_FromString(self->msginfo->subject);
256 static PyObject* get_MessageID(clawsmail_MessageInfoObject *self, void *closure)
258 if(self->msginfo && self->msginfo->msgid)
259 return PyString_FromString(self->msginfo->msgid);
263 static PyObject* get_FilePath(clawsmail_MessageInfoObject *self, void *closure)
267 filepath = procmsg_get_message_file_path(self->msginfo);
270 retval = PyString_FromString(filepath);
278 static PyObject* get_flag(clawsmail_MessageInfoObject *self, void *closure)
281 int flag = GPOINTER_TO_INT(closure);
282 return py_boolean_return_value(((self->msginfo->flags.perm_flags & flag) != 0));
287 static int set_flag(clawsmail_MessageInfoObject *self, PyObject *value, void *closure)
289 int flag = GPOINTER_TO_INT(closure);
292 PyErr_SetString(PyExc_TypeError, "Cannot delete flag attribute");
297 PyErr_SetString(PyExc_RuntimeError, "MessageInfo object broken");
301 if(PyObject_IsTrue(value))
302 procmsg_msginfo_set_flags(self->msginfo, flag, 0);
304 procmsg_msginfo_unset_flags(self->msginfo, flag, 0);
309 static PyMethodDef MessageInfo_methods[] = {
310 {"is_new", is_new, METH_NOARGS,
311 "is_new() - checks if the message is new\n"
313 "Returns True if the new flag of the message is set."
314 "\n\nThis function is deprecated in favor of the 'new' attribute."},
316 {"is_unread", is_unread, METH_NOARGS,
317 "is_unread() - checks if the message is unread\n"
319 "Returns True if the unread flag of the message is set."
320 "\n\nThis function is deprecated in favor of the 'unread' attribute."},
322 {"is_marked", is_marked, METH_NOARGS,
323 "is_marked() - checks if the message is marked\n"
325 "Returns True if the marked flag of the message is set."
326 "\n\nThis function is deprecated in favor of the 'marked' attribute."},
328 {"is_replied", is_replied, METH_NOARGS,
329 "is_replied() - checks if the message has been replied to\n"
331 "Returns True if the replied flag of the message is set."
332 "\n\nThis function is deprecated in favor of the 'replied' attribute."},
334 {"is_locked", is_locked, METH_NOARGS,
335 "is_locked() - checks if the message has been locked\n"
337 "Returns True if the locked flag of the message is set."
338 "\n\nThis function is deprecated in favor of the 'locked' attribute."},
340 {"is_forwarded", is_forwarded, METH_NOARGS,
341 "is_forwarded() - checks if the message has been forwarded\n"
343 "Returns True if the forwarded flag of the message is set."
344 "\n\nThis function is deprecated in favor of the 'forwarded' attribute."},
346 {"get_tags", get_tags, METH_NOARGS,
347 "get_tags() - get message tags\n"
349 "Returns a tuple of tags that apply to this message."},
351 {"add_tag", add_tag, METH_VARARGS,
352 "add_tag(tag) - add a tag to this message\n"
354 "Add a tag to this message. If the tag is already set, nothing is done.\n"
355 "If the tag does not exist, a ValueError exception is raised."},
357 {"remove_tag", remove_tag, METH_VARARGS,
358 "remove_tag(tag) - remove a tag from this message\n"
360 "Remove a tag from this message. If the tag is not set, a KeyError exception is raised.\n"
361 "If the tag does not exist, a ValueError exception is raised."},
363 {"get_header", get_header, METH_VARARGS,
364 "get_header(name) - get a message header with a given name\n"
366 "Get a message header content with a given name. If the header does not exist,\n"
367 "the value 'None' is returned. If multiple headers with the same name exist,\n"
368 "the first one is returned."},
373 static PyGetSetDef MessageInfo_getset[] = {
374 { "From", (getter)get_From, (setter)NULL,
375 "From - the From header of the message", NULL},
377 { "To", (getter)get_To, (setter)NULL,
378 "To - the To header of the message", NULL },
380 { "Cc", (getter)get_Cc, (setter)NULL,
381 "Cc - the Cc header of the message", NULL },
383 {"Subject", (getter)get_Subject, (setter)NULL,
384 "Subject - the subject header of the message", NULL},
386 {"MessageID", (getter)get_MessageID, (setter)NULL,
387 "MessageID - the Message-ID header of the message", NULL},
389 {"FilePath", (getter)get_FilePath, (setter)NULL,
390 "FilePath - path and filename of the message", NULL},
392 {"unread", (getter)get_flag, (setter)set_flag,
393 "unread - Unread-flag of the message", GINT_TO_POINTER(MSG_UNREAD)},
395 {"locked", (getter)get_flag, (setter)set_flag,
396 "locked - Locked-flag of the message", GINT_TO_POINTER(MSG_LOCKED)},
398 {"marked", (getter)get_flag, (setter)set_flag,
399 "marked - Marked-flag of the message", GINT_TO_POINTER(MSG_MARKED)},
401 {"new", (getter)get_flag, (setter)NULL,
402 "new - new-flag of the message", GINT_TO_POINTER(MSG_NEW)},
404 {"replied", (getter)get_flag, (setter)NULL,
405 "replied - Replied-flag of the message", GINT_TO_POINTER(MSG_REPLIED)},
407 {"forwarded", (getter)get_flag, (setter)NULL,
408 "forwarded - Forwarded-flag of the message", GINT_TO_POINTER(MSG_FORWARDED)},
414 static PyTypeObject clawsmail_MessageInfoType = {
415 PyObject_HEAD_INIT(NULL)
417 "clawsmail.MessageInfo", /* tp_name*/
418 sizeof(clawsmail_MessageInfoObject), /* tp_basicsize*/
420 (destructor)MessageInfo_dealloc, /* tp_dealloc*/
427 0, /* tp_as_sequence*/
428 0, /* tp_as_mapping*/
431 (reprfunc)MessageInfo_str, /* tp_str*/
435 Py_TPFLAGS_DEFAULT, /* tp_flags*/
436 "A MessageInfo represents" /* tp_doc */
437 " a single message.\n\n"
438 "Do not construct objects of this type yourself.",
441 0, /* tp_richcompare */
442 0, /* tp_weaklistoffset */
445 MessageInfo_methods, /* tp_methods */
447 MessageInfo_getset, /* tp_getset */
450 0, /* tp_descr_get */
451 0, /* tp_descr_set */
452 0, /* tp_dictoffset */
453 (initproc)MessageInfo_init,/* tp_init */
458 gboolean cmpy_add_messageinfo(PyObject *module)
460 clawsmail_MessageInfoType.tp_new = PyType_GenericNew;
461 if(PyType_Ready(&clawsmail_MessageInfoType) < 0)
464 Py_INCREF(&clawsmail_MessageInfoType);
465 return (PyModule_AddObject(module, "MessageInfo", (PyObject*)&clawsmail_MessageInfoType) == 0);
468 PyObject* clawsmail_messageinfo_new(MsgInfo *msginfo)
470 clawsmail_MessageInfoObject *ff;
475 ff = (clawsmail_MessageInfoObject*) PyObject_CallObject((PyObject*) &clawsmail_MessageInfoType, NULL);
479 ff->msginfo = msginfo;
480 return (PyObject*)ff;
483 PyTypeObject* clawsmail_messageinfo_get_type_object()
485 return &clawsmail_MessageInfoType;
488 MsgInfo* clawsmail_messageinfo_get_msginfo(PyObject *self)
490 return ((clawsmail_MessageInfoObject*)self)->msginfo;