1 /* Python plugin for Claws-Mail
2 * Copyright (C) 2009-2012 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"
24 #include <glib/gi18n.h>
26 #include "messageinfotype.h"
28 #include "common/tags.h"
29 #include "common/defs.h"
30 #include "mainwindow.h"
31 #include "summaryview.h"
32 #include "procheader.h"
34 #include <structmember.h>
38 #define HEADER_CONTENT_SIZE BUFFSIZE
49 } clawsmail_MessageInfoObject;
52 static void MessageInfo_dealloc(clawsmail_MessageInfoObject* self)
54 Py_XDECREF(self->from);
57 Py_XDECREF(self->subject);
58 Py_XDECREF(self->msgid);
59 self->ob_type->tp_free((PyObject*)self);
62 static int MessageInfo_init(clawsmail_MessageInfoObject *self, PyObject *args, PyObject *kwds)
74 self->subject = Py_None;
77 self->msgid = Py_None;
82 static PyObject* MessageInfo_str(PyObject *self)
85 str = PyString_FromString("MessageInfo: ");
86 PyString_ConcatAndDel(&str, PyObject_GetAttrString(self, "From"));
87 PyString_ConcatAndDel(&str, PyString_FromString(" / "));
88 PyString_ConcatAndDel(&str, PyObject_GetAttrString(self, "Subject"));
92 static PyObject *py_boolean_return_value(gboolean val)
104 static PyObject *is_new(PyObject *self, PyObject *args)
106 return py_boolean_return_value(MSG_IS_NEW(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
109 static PyObject *is_unread(PyObject *self, PyObject *args)
111 return py_boolean_return_value(MSG_IS_UNREAD(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
114 static PyObject *is_marked(PyObject *self, PyObject *args)
116 return py_boolean_return_value(MSG_IS_MARKED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
119 static PyObject *is_replied(PyObject *self, PyObject *args)
121 return py_boolean_return_value(MSG_IS_REPLIED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
124 static PyObject *is_locked(PyObject *self, PyObject *args)
126 return py_boolean_return_value(MSG_IS_LOCKED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
129 static PyObject *is_forwarded(PyObject *self, PyObject *args)
131 return py_boolean_return_value(MSG_IS_FORWARDED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
134 static PyObject* get_tags(PyObject *self, PyObject *args)
138 PyObject *tags_tuple;
140 tags_list = ((clawsmail_MessageInfoObject*)self)->msginfo->tags;
141 num_tags = g_slist_length(tags_list);
143 tags_tuple = PyTuple_New(num_tags);
144 if(tags_tuple != NULL) {
146 PyObject *tag_object;
150 for(walk = tags_list; walk; walk = walk->next) {
151 tag_object = Py_BuildValue("s", tags_get_tag(GPOINTER_TO_INT(walk->data)));
152 if(tag_object == NULL) {
153 Py_DECREF(tags_tuple);
156 PyTuple_SET_ITEM(tags_tuple, iTag++, tag_object);
164 static PyObject* add_or_remove_tag(PyObject *self, PyObject *args, gboolean add)
172 retval = PyArg_ParseTuple(args, "s", &tag_str);
176 tag_id = tags_get_id_for_str(tag_str);
178 PyErr_SetString(PyExc_ValueError, "Tag does not exist");
182 msginfo = ((clawsmail_MessageInfoObject*)self)->msginfo;
185 /* raise KeyError if tag is not set */
186 if(!g_slist_find(msginfo->tags, GINT_TO_POINTER(tag_id))) {
187 PyErr_SetString(PyExc_KeyError, "Tag is not set on this message");
192 procmsg_msginfo_update_tags(msginfo, add, tag_id);
195 mainwin = mainwindow_get_mainwindow();
197 summary_redisplay_msg(mainwin->summaryview);
204 static PyObject* add_tag(PyObject *self, PyObject *args)
206 return add_or_remove_tag(self, args, TRUE);
210 static PyObject* remove_tag(PyObject *self, PyObject *args)
212 return add_or_remove_tag(self, args, FALSE);
215 static PyObject* get_header(PyObject *self, PyObject *args)
218 const char *header_str;
219 char *header_str_dup;
221 gchar header_content[HEADER_CONTENT_SIZE];
223 retval = PyArg_ParseTuple(args, "s", &header_str);
227 msginfo = ((clawsmail_MessageInfoObject*)self)->msginfo;
229 header_str_dup = g_strdup(header_str);
230 retval = procheader_get_header_from_msginfo(msginfo, header_content, HEADER_CONTENT_SIZE, header_str);
231 g_free(header_str_dup);
233 PyObject *header_content_object;
234 gchar *content_start;
236 /* the string is now Header: Value. Strip the Header: part */
237 content_start = strstr(header_content, ":");
238 if(content_start == NULL)
239 content_start = header_content;
242 /* strip leading spaces */
243 while(*content_start == ' ')
245 header_content_object = Py_BuildValue("s", content_start);
246 return header_content_object;
254 static PyMethodDef MessageInfo_methods[] = {
255 {"is_new", is_new, METH_NOARGS,
256 "is_new() - checks if the message is new\n"
258 "Returns True if the new flag of the message is set."},
260 {"is_unread", is_unread, METH_NOARGS,
261 "is_unread() - checks if the message is unread\n"
263 "Returns True if the unread flag of the message is set."},
265 {"is_marked", is_marked, METH_NOARGS,
266 "is_marked() - checks if the message is marked\n"
268 "Returns True if the marked flag of the message is set."},
270 {"is_replied", is_replied, METH_NOARGS,
271 "is_replied() - checks if the message has been replied to\n"
273 "Returns True if the replied flag of the message is set."},
275 {"is_locked", is_locked, METH_NOARGS,
276 "is_locked() - checks if the message has been locked\n"
278 "Returns True if the locked flag of the message is set."},
280 {"is_forwarded", is_forwarded, METH_NOARGS,
281 "is_forwarded() - checks if the message has been forwarded\n"
283 "Returns True if the forwarded flag of the message is set."},
285 {"get_tags", get_tags, METH_NOARGS,
286 "get_tags() - get message tags\n"
288 "Returns a tuple of tags that apply to this message."},
290 {"add_tag", add_tag, METH_VARARGS,
291 "add_tag(tag) - add a tag to this message\n"
293 "Add a tag to this message. If the tag is already set, nothing is done.\n"
294 "If the tag does not exist, a ValueError exception is raised."},
296 {"remove_tag", remove_tag, METH_VARARGS,
297 "remove_tag(tag) - remove a tag from this message\n"
299 "Remove a tag from this message. If the tag is not set, a KeyError exception is raised.\n"
300 "If the tag does not exist, a ValueError exception is raised."},
302 {"get_header", get_header, METH_VARARGS,
303 "get_header(name) - get a message header with a given name\n"
305 "Get a message header content with a given name. If the header does not exist,\n"
306 "the value 'None' is returned. If multiple headers with the same name exist,\n"
307 "the first one is returned."},
312 static PyMemberDef MessageInfo_members[] = {
313 { "From", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, from), 0,
314 "From - the From header of the message" },
316 { "To", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, to), 0,
317 "To - the To header of the message" },
319 { "Cc", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, cc), 0,
320 "Cc - the Cc header of the message" },
322 {"Subject", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, subject), 0,
323 "Subject - the subject header of the message"},
325 {"MessageID", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, msgid), 0,
326 "MessageID - the Message-ID header of the message"},
328 {"FilePath", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, filepath), 0,
329 "FilePath - path and filename of the message"},
334 static PyTypeObject clawsmail_MessageInfoType = {
335 PyObject_HEAD_INIT(NULL)
337 "clawsmail.MessageInfo", /* tp_name*/
338 sizeof(clawsmail_MessageInfoObject), /* tp_basicsize*/
340 (destructor)MessageInfo_dealloc, /* tp_dealloc*/
347 0, /* tp_as_sequence*/
348 0, /* tp_as_mapping*/
351 MessageInfo_str, /* tp_str*/
355 Py_TPFLAGS_DEFAULT, /* tp_flags*/
356 "A MessageInfo represents" /* tp_doc */
360 0, /* tp_richcompare */
361 0, /* tp_weaklistoffset */
364 MessageInfo_methods, /* tp_methods */
365 MessageInfo_members, /* tp_members */
369 0, /* tp_descr_get */
370 0, /* tp_descr_set */
371 0, /* tp_dictoffset */
372 (initproc)MessageInfo_init,/* tp_init */
377 PyMODINIT_FUNC initmessageinfo(PyObject *module)
379 clawsmail_MessageInfoType.tp_new = PyType_GenericNew;
380 if(PyType_Ready(&clawsmail_MessageInfoType) < 0)
383 Py_INCREF(&clawsmail_MessageInfoType);
384 PyModule_AddObject(module, "MessageInfo", (PyObject*)&clawsmail_MessageInfoType);
387 #define MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(fis, pms) \
391 str = PyString_FromString(fis); \
394 retval = PyObject_SetAttrString((PyObject*)ff, pms, str); \
402 static gboolean update_members(clawsmail_MessageInfoObject *ff, MsgInfo *msginfo)
406 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->from, "From");
407 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->to, "To");
408 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->cc, "Cc");
409 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->subject, "Subject");
410 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->msgid, "MessageID");
412 filepath = procmsg_get_message_file_path(msginfo);
414 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(filepath, "FilePath");
418 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER("", "FilePath");
426 PyObject* clawsmail_messageinfo_new(MsgInfo *msginfo)
428 clawsmail_MessageInfoObject *ff;
433 ff = (clawsmail_MessageInfoObject*) PyObject_CallObject((PyObject*) &clawsmail_MessageInfoType, NULL);
437 ff->msginfo = msginfo;
439 if(update_members(ff, msginfo))
440 return (PyObject*)ff;
447 PyTypeObject* clawsmail_messageinfo_get_type_object()
449 return &clawsmail_MessageInfoType;
452 MsgInfo* clawsmail_messageinfo_get_msginfo(PyObject *self)
454 return ((clawsmail_MessageInfoObject*)self)->msginfo;