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"
23 #include <glib/gi18n.h>
25 #include "messageinfotype.h"
27 #include "common/tags.h"
28 #include "common/defs.h"
29 #include "mainwindow.h"
30 #include "summaryview.h"
31 #include "procheader.h"
33 #include <structmember.h>
37 #define HEADER_CONTENT_SIZE BUFFSIZE
48 } clawsmail_MessageInfoObject;
51 static void MessageInfo_dealloc(clawsmail_MessageInfoObject* self)
53 Py_XDECREF(self->from);
56 Py_XDECREF(self->subject);
57 Py_XDECREF(self->msgid);
58 self->ob_type->tp_free((PyObject*)self);
61 static int MessageInfo_init(clawsmail_MessageInfoObject *self, PyObject *args, PyObject *kwds)
73 self->subject = Py_None;
76 self->msgid = Py_None;
81 static PyObject* MessageInfo_str(PyObject *self)
84 str = PyString_FromString("MessageInfo: ");
85 PyString_ConcatAndDel(&str, PyObject_GetAttrString(self, "From"));
86 PyString_ConcatAndDel(&str, PyString_FromString(" / "));
87 PyString_ConcatAndDel(&str, PyObject_GetAttrString(self, "Subject"));
91 static PyObject *py_boolean_return_value(gboolean val)
103 static PyObject *is_new(PyObject *self, PyObject *args)
105 return py_boolean_return_value(MSG_IS_NEW(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
108 static PyObject *is_unread(PyObject *self, PyObject *args)
110 return py_boolean_return_value(MSG_IS_UNREAD(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
113 static PyObject *is_marked(PyObject *self, PyObject *args)
115 return py_boolean_return_value(MSG_IS_MARKED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
118 static PyObject *is_replied(PyObject *self, PyObject *args)
120 return py_boolean_return_value(MSG_IS_REPLIED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
123 static PyObject *is_locked(PyObject *self, PyObject *args)
125 return py_boolean_return_value(MSG_IS_LOCKED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
128 static PyObject *is_forwarded(PyObject *self, PyObject *args)
130 return py_boolean_return_value(MSG_IS_FORWARDED(((clawsmail_MessageInfoObject*)self)->msginfo->flags));
133 static PyObject* get_tags(PyObject *self, PyObject *args)
137 PyObject *tags_tuple;
139 tags_list = ((clawsmail_MessageInfoObject*)self)->msginfo->tags;
140 num_tags = g_slist_length(tags_list);
142 tags_tuple = PyTuple_New(num_tags);
143 if(tags_tuple != NULL) {
145 PyObject *tag_object;
149 for(walk = tags_list; walk; walk = walk->next) {
150 tag_object = Py_BuildValue("s", tags_get_tag(GPOINTER_TO_INT(walk->data)));
151 if(tag_object == NULL) {
152 Py_DECREF(tags_tuple);
155 PyTuple_SET_ITEM(tags_tuple, iTag++, tag_object);
163 static PyObject* add_or_remove_tag(PyObject *self, PyObject *args, gboolean add)
171 retval = PyArg_ParseTuple(args, "s", &tag_str);
175 tag_id = tags_get_id_for_str(tag_str);
177 PyErr_SetString(PyExc_ValueError, "Tag does not exist");
181 msginfo = ((clawsmail_MessageInfoObject*)self)->msginfo;
184 /* raise KeyError if tag is not set */
185 if(!g_slist_find(msginfo->tags, GINT_TO_POINTER(tag_id))) {
186 PyErr_SetString(PyExc_KeyError, "Tag is not set on this message");
191 procmsg_msginfo_update_tags(msginfo, add, tag_id);
194 mainwin = mainwindow_get_mainwindow();
196 summary_redisplay_msg(mainwin->summaryview);
203 static PyObject* add_tag(PyObject *self, PyObject *args)
205 return add_or_remove_tag(self, args, TRUE);
209 static PyObject* remove_tag(PyObject *self, PyObject *args)
211 return add_or_remove_tag(self, args, FALSE);
214 static PyObject* get_header(PyObject *self, PyObject *args)
217 const char *header_str;
218 char *header_str_dup;
220 gchar header_content[HEADER_CONTENT_SIZE];
222 retval = PyArg_ParseTuple(args, "s", &header_str);
226 msginfo = ((clawsmail_MessageInfoObject*)self)->msginfo;
228 header_str_dup = g_strdup(header_str);
229 retval = procheader_get_header_from_msginfo(msginfo, header_content, HEADER_CONTENT_SIZE, header_str);
230 g_free(header_str_dup);
232 PyObject *header_content_object;
233 gchar *content_start;
235 /* the string is now Header: Value. Strip the Header: part */
236 content_start = strstr(header_content, ":");
237 if(content_start == NULL)
238 content_start = header_content;
241 /* strip leading spaces */
242 while(*content_start == ' ')
244 header_content_object = Py_BuildValue("s", content_start);
245 return header_content_object;
253 static PyMethodDef MessageInfo_methods[] = {
254 {"is_new", is_new, METH_NOARGS,
255 "is_new() - checks if the message is new\n"
257 "Returns True if the new flag of the message is set."},
259 {"is_unread", is_unread, METH_NOARGS,
260 "is_unread() - checks if the message is unread\n"
262 "Returns True if the unread flag of the message is set."},
264 {"is_marked", is_marked, METH_NOARGS,
265 "is_marked() - checks if the message is marked\n"
267 "Returns True if the marked flag of the message is set."},
269 {"is_replied", is_replied, METH_NOARGS,
270 "is_replied() - checks if the message has been replied to\n"
272 "Returns True if the replied flag of the message is set."},
274 {"is_locked", is_locked, METH_NOARGS,
275 "is_locked() - checks if the message has been locked\n"
277 "Returns True if the locked flag of the message is set."},
279 {"is_forwarded", is_forwarded, METH_NOARGS,
280 "is_forwarded() - checks if the message has been forwarded\n"
282 "Returns True if the forwarded flag of the message is set."},
284 {"get_tags", get_tags, METH_NOARGS,
285 "get_tags() - get message tags\n"
287 "Returns a tuple of tags that apply to this message."},
289 {"add_tag", add_tag, METH_VARARGS,
290 "add_tag(tag) - add a tag to this message\n"
292 "Add a tag to this message. If the tag is already set, nothing is done.\n"
293 "If the tag does not exist, a ValueError exception is raised."},
295 {"remove_tag", remove_tag, METH_VARARGS,
296 "remove_tag(tag) - remove a tag from this message\n"
298 "Remove a tag from this message. If the tag is not set, a KeyError exception is raised.\n"
299 "If the tag does not exist, a ValueError exception is raised."},
301 {"get_header", get_header, METH_VARARGS,
302 "get_header(name) - get a message header with a given name\n"
304 "Get a message header content with a given name. If the header does not exist,\n"
305 "the value 'None' is returned. If multiple headers with the same name exist,\n"
306 "the first one is returned."},
311 static PyMemberDef MessageInfo_members[] = {
312 { "From", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, from), 0,
313 "From - the From header of the message" },
315 { "To", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, to), 0,
316 "To - the To header of the message" },
318 { "Cc", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, cc), 0,
319 "Cc - the Cc header of the message" },
321 {"Subject", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, subject), 0,
322 "Subject - the subject header of the message"},
324 {"MessageID", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, msgid), 0,
325 "MessageID - the Message-ID header of the message"},
327 {"FilePath", T_OBJECT_EX, offsetof(clawsmail_MessageInfoObject, filepath), 0,
328 "FilePath - path and filename of the message"},
333 static PyTypeObject clawsmail_MessageInfoType = {
334 PyObject_HEAD_INIT(NULL)
336 "clawsmail.MessageInfo", /* tp_name*/
337 sizeof(clawsmail_MessageInfoObject), /* tp_basicsize*/
339 (destructor)MessageInfo_dealloc, /* tp_dealloc*/
346 0, /* tp_as_sequence*/
347 0, /* tp_as_mapping*/
350 MessageInfo_str, /* tp_str*/
354 Py_TPFLAGS_DEFAULT, /* tp_flags*/
355 "A MessageInfo represents" /* tp_doc */
359 0, /* tp_richcompare */
360 0, /* tp_weaklistoffset */
363 MessageInfo_methods, /* tp_methods */
364 MessageInfo_members, /* tp_members */
368 0, /* tp_descr_get */
369 0, /* tp_descr_set */
370 0, /* tp_dictoffset */
371 (initproc)MessageInfo_init,/* tp_init */
376 gboolean cmpy_add_messageinfo(PyObject *module)
378 clawsmail_MessageInfoType.tp_new = PyType_GenericNew;
379 if(PyType_Ready(&clawsmail_MessageInfoType) < 0)
382 Py_INCREF(&clawsmail_MessageInfoType);
383 return (PyModule_AddObject(module, "MessageInfo", (PyObject*)&clawsmail_MessageInfoType) == 0);
386 #define MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(fis, pms) \
390 str = PyString_FromString(fis); \
393 retval = PyObject_SetAttrString((PyObject*)ff, pms, str); \
401 static gboolean update_members(clawsmail_MessageInfoObject *ff, MsgInfo *msginfo)
405 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->from, "From");
406 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->to, "To");
407 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->cc, "Cc");
408 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->subject, "Subject");
409 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(msginfo->msgid, "MessageID");
411 filepath = procmsg_get_message_file_path(msginfo);
413 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER(filepath, "FilePath");
417 MSGINFO_STRING_TO_PYTHON_MESSAGEINFO_MEMBER("", "FilePath");
425 PyObject* clawsmail_messageinfo_new(MsgInfo *msginfo)
427 clawsmail_MessageInfoObject *ff;
432 ff = (clawsmail_MessageInfoObject*) PyObject_CallObject((PyObject*) &clawsmail_MessageInfoType, NULL);
436 ff->msginfo = msginfo;
438 if(update_members(ff, msginfo))
439 return (PyObject*)ff;
446 PyTypeObject* clawsmail_messageinfo_get_type_object()
448 return &clawsmail_MessageInfoType;
451 MsgInfo* clawsmail_messageinfo_get_msginfo(PyObject *self)
453 return ((clawsmail_MessageInfoObject*)self)->msginfo;