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"
24 #include "foldertype.h"
26 #include "common/tags.h"
27 #include "common/defs.h"
28 #include "mainwindow.h"
29 #include "summaryview.h"
30 #include "procheader.h"
32 #include <glib/gi18n.h>
34 #include <structmember.h>
41 } clawsmail_MessageInfoObject
;
44 static void MessageInfo_dealloc(clawsmail_MessageInfoObject
* self
)
46 Py_TYPE(self
)->tp_free((PyObject
*)self
);
49 static int MessageInfo_init(clawsmail_MessageInfoObject
*self
, PyObject
*args
, PyObject
*kwds
)
54 static PyObject
* MessageInfo_str(clawsmail_MessageInfoObject
*self
)
59 From
= self
->msginfo
->from
? self
->msginfo
->from
: "";
60 Subject
= self
->msginfo
->subject
? self
->msginfo
->subject
: "";
61 return PyUnicode_FromFormat("MessageInfo: %s / %s", From
, Subject
);
66 static PyObject
*py_boolean_return_value(gboolean val
)
78 static PyObject
*is_new(PyObject
*self
, PyObject
*args
)
80 return py_boolean_return_value(MSG_IS_NEW(((clawsmail_MessageInfoObject
*)self
)->msginfo
->flags
));
83 static PyObject
*is_unread(PyObject
*self
, PyObject
*args
)
85 return py_boolean_return_value(MSG_IS_UNREAD(((clawsmail_MessageInfoObject
*)self
)->msginfo
->flags
));
88 static PyObject
*is_marked(PyObject
*self
, PyObject
*args
)
90 return py_boolean_return_value(MSG_IS_MARKED(((clawsmail_MessageInfoObject
*)self
)->msginfo
->flags
));
93 static PyObject
*is_replied(PyObject
*self
, PyObject
*args
)
95 return py_boolean_return_value(MSG_IS_REPLIED(((clawsmail_MessageInfoObject
*)self
)->msginfo
->flags
));
98 static PyObject
*is_locked(PyObject
*self
, PyObject
*args
)
100 return py_boolean_return_value(MSG_IS_LOCKED(((clawsmail_MessageInfoObject
*)self
)->msginfo
->flags
));
103 static PyObject
*is_forwarded(PyObject
*self
, PyObject
*args
)
105 return py_boolean_return_value(MSG_IS_FORWARDED(((clawsmail_MessageInfoObject
*)self
)->msginfo
->flags
));
108 static PyObject
* get_tags(PyObject
*self
, PyObject
*args
)
112 PyObject
*tags_tuple
;
114 tags_list
= ((clawsmail_MessageInfoObject
*)self
)->msginfo
->tags
;
115 num_tags
= g_slist_length(tags_list
);
117 tags_tuple
= PyTuple_New(num_tags
);
118 if(tags_tuple
!= NULL
) {
120 PyObject
*tag_object
;
124 for(walk
= tags_list
; walk
; walk
= walk
->next
) {
125 tag_object
= Py_BuildValue("s", tags_get_tag(GPOINTER_TO_INT(walk
->data
)));
126 if(tag_object
== NULL
) {
127 Py_DECREF(tags_tuple
);
130 PyTuple_SET_ITEM(tags_tuple
, iTag
++, tag_object
);
138 static PyObject
* add_or_remove_tag(PyObject
*self
, PyObject
*args
, gboolean add
)
146 retval
= PyArg_ParseTuple(args
, "s", &tag_str
);
150 tag_id
= tags_get_id_for_str(tag_str
);
152 PyErr_SetString(PyExc_ValueError
, "Tag does not exist");
156 msginfo
= ((clawsmail_MessageInfoObject
*)self
)->msginfo
;
159 /* raise KeyError if tag is not set */
160 if(!g_slist_find(msginfo
->tags
, GINT_TO_POINTER(tag_id
))) {
161 PyErr_SetString(PyExc_KeyError
, "Tag is not set on this message");
166 procmsg_msginfo_update_tags(msginfo
, add
, tag_id
);
169 mainwin
= mainwindow_get_mainwindow();
171 summary_redisplay_msg(mainwin
->summaryview
);
178 static PyObject
* add_tag(PyObject
*self
, PyObject
*args
)
180 return add_or_remove_tag(self
, args
, TRUE
);
184 static PyObject
* remove_tag(PyObject
*self
, PyObject
*args
)
186 return add_or_remove_tag(self
, args
, FALSE
);
189 static PyObject
* get_header(PyObject
*self
, PyObject
*args
)
193 char *header_str_dup
;
195 gchar
*header_content
= NULL
;
197 retval
= PyArg_ParseTuple(args
, "s", &header_str
);
201 msginfo
= ((clawsmail_MessageInfoObject
*)self
)->msginfo
;
203 header_str_dup
= g_strdup(header_str
);
204 retval
= procheader_get_header_from_msginfo(msginfo
, &header_content
, header_str
);
205 g_free(header_str_dup
);
207 PyObject
*header_content_object
;
208 gchar
*content_start
;
210 /* the string is now Header: Value. Strip the Header: part */
211 content_start
= strstr(header_content
, ":");
212 if(content_start
== NULL
)
213 content_start
= header_content
;
216 /* strip leading spaces */
217 while(*content_start
== ' ')
219 header_content_object
= Py_BuildValue("s", content_start
);
220 g_free(header_content
);
221 return header_content_object
;
224 g_free(header_content
);
229 static PyObject
* get_From(clawsmail_MessageInfoObject
*self
, void *closure
)
231 if(self
->msginfo
&& self
->msginfo
->from
)
232 return PyUnicode_FromString(self
->msginfo
->from
);
236 static PyObject
* get_To(clawsmail_MessageInfoObject
*self
, void *closure
)
238 if(self
->msginfo
&& self
->msginfo
->to
)
239 return PyUnicode_FromString(self
->msginfo
->to
);
243 static PyObject
* get_Cc(clawsmail_MessageInfoObject
*self
, void *closure
)
245 if(self
->msginfo
&& self
->msginfo
->cc
)
246 return PyUnicode_FromString(self
->msginfo
->cc
);
250 static PyObject
* get_Subject(clawsmail_MessageInfoObject
*self
, void *closure
)
252 if(self
->msginfo
&& self
->msginfo
->subject
)
253 return PyUnicode_FromString(self
->msginfo
->subject
);
257 static PyObject
* get_MessageID(clawsmail_MessageInfoObject
*self
, void *closure
)
259 if(self
->msginfo
&& self
->msginfo
->msgid
)
260 return PyUnicode_FromString(self
->msginfo
->msgid
);
264 static PyObject
* get_FilePath(clawsmail_MessageInfoObject
*self
, void *closure
)
268 filepath
= procmsg_get_message_file_path(self
->msginfo
);
271 retval
= PyUnicode_FromString(filepath
);
279 static PyObject
* get_flag(clawsmail_MessageInfoObject
*self
, void *closure
)
282 int flag
= GPOINTER_TO_INT(closure
);
283 return py_boolean_return_value(((self
->msginfo
->flags
.perm_flags
& flag
) != 0));
288 static int set_flag(clawsmail_MessageInfoObject
*self
, PyObject
*value
, void *closure
)
290 int flag
= GPOINTER_TO_INT(closure
);
293 PyErr_SetString(PyExc_TypeError
, "Cannot delete flag attribute");
298 PyErr_SetString(PyExc_RuntimeError
, "MessageInfo object broken");
302 if(PyObject_IsTrue(value
))
303 procmsg_msginfo_set_flags(self
->msginfo
, flag
, 0);
305 procmsg_msginfo_unset_flags(self
->msginfo
, flag
, 0);
311 static PyObject
* get_Folder(clawsmail_MessageInfoObject
*self
, void *closure
)
313 if(self
->msginfo
&& self
->msginfo
->folder
) {
314 return clawsmail_folder_new(self
->msginfo
->folder
);
320 static PyMethodDef MessageInfo_methods
[] = {
321 {"is_new", is_new
, METH_NOARGS
,
322 "is_new() - checks if the message is new\n"
324 "Returns True if the new flag of the message is set."
325 "\n\nThis function is deprecated in favor of the 'new' attribute."},
327 {"is_unread", is_unread
, METH_NOARGS
,
328 "is_unread() - checks if the message is unread\n"
330 "Returns True if the unread flag of the message is set."
331 "\n\nThis function is deprecated in favor of the 'unread' attribute."},
333 {"is_marked", is_marked
, METH_NOARGS
,
334 "is_marked() - checks if the message is marked\n"
336 "Returns True if the marked flag of the message is set."
337 "\n\nThis function is deprecated in favor of the 'marked' attribute."},
339 {"is_replied", is_replied
, METH_NOARGS
,
340 "is_replied() - checks if the message has been replied to\n"
342 "Returns True if the replied flag of the message is set."
343 "\n\nThis function is deprecated in favor of the 'replied' attribute."},
345 {"is_locked", is_locked
, METH_NOARGS
,
346 "is_locked() - checks if the message has been locked\n"
348 "Returns True if the locked flag of the message is set."
349 "\n\nThis function is deprecated in favor of the 'locked' attribute."},
351 {"is_forwarded", is_forwarded
, METH_NOARGS
,
352 "is_forwarded() - checks if the message has been forwarded\n"
354 "Returns True if the forwarded flag of the message is set."
355 "\n\nThis function is deprecated in favor of the 'forwarded' attribute."},
357 {"get_tags", get_tags
, METH_NOARGS
,
358 "get_tags() - get message tags\n"
360 "Returns a tuple of tags that apply to this message."},
362 {"add_tag", add_tag
, METH_VARARGS
,
363 "add_tag(tag) - add a tag to this message\n"
365 "Add a tag to this message. If the tag is already set, nothing is done.\n"
366 "If the tag does not exist, a ValueError exception is raised."},
368 {"remove_tag", remove_tag
, METH_VARARGS
,
369 "remove_tag(tag) - remove a tag from this message\n"
371 "Remove a tag from this message. If the tag is not set, a KeyError exception is raised.\n"
372 "If the tag does not exist, a ValueError exception is raised."},
374 {"get_header", get_header
, METH_VARARGS
,
375 "get_header(name) - get a message header with a given name\n"
377 "Get a message header content with a given name. If the header does not exist,\n"
378 "the value 'None' is returned. If multiple headers with the same name exist,\n"
379 "the first one is returned."},
384 static PyGetSetDef MessageInfo_getset
[] = {
385 { "From", (getter
)get_From
, (setter
)NULL
,
386 "From - the From header of the message", NULL
},
388 { "To", (getter
)get_To
, (setter
)NULL
,
389 "To - the To header of the message", NULL
},
391 { "Cc", (getter
)get_Cc
, (setter
)NULL
,
392 "Cc - the Cc header of the message", NULL
},
394 {"Subject", (getter
)get_Subject
, (setter
)NULL
,
395 "Subject - the subject header of the message", NULL
},
397 {"MessageID", (getter
)get_MessageID
, (setter
)NULL
,
398 "MessageID - the Message-ID header of the message", NULL
},
400 {"FilePath", (getter
)get_FilePath
, (setter
)NULL
,
401 "FilePath - path and filename of the message", NULL
},
403 {"unread", (getter
)get_flag
, (setter
)set_flag
,
404 "unread - Unread-flag of the message", GINT_TO_POINTER(MSG_UNREAD
)},
406 {"locked", (getter
)get_flag
, (setter
)set_flag
,
407 "locked - Locked-flag of the message", GINT_TO_POINTER(MSG_LOCKED
)},
409 {"marked", (getter
)get_flag
, (setter
)set_flag
,
410 "marked - Marked-flag of the message", GINT_TO_POINTER(MSG_MARKED
)},
412 {"new", (getter
)get_flag
, (setter
)NULL
,
413 "new - new-flag of the message", GINT_TO_POINTER(MSG_NEW
)},
415 {"replied", (getter
)get_flag
, (setter
)NULL
,
416 "replied - Replied-flag of the message", GINT_TO_POINTER(MSG_REPLIED
)},
418 {"forwarded", (getter
)get_flag
, (setter
)NULL
,
419 "forwarded - Forwarded-flag of the message", GINT_TO_POINTER(MSG_FORWARDED
)},
421 {"Folder", (getter
)get_Folder
, (setter
)NULL
,
422 "Folder - Folder in which the message is contained", NULL
},
428 static PyTypeObject clawsmail_MessageInfoType
= {
429 PyVarObject_HEAD_INIT(NULL
, 0)
430 "clawsmail.MessageInfo", /* tp_name*/
431 sizeof(clawsmail_MessageInfoObject
), /* tp_basicsize*/
433 (destructor
)MessageInfo_dealloc
, /* tp_dealloc*/
440 0, /* tp_as_sequence*/
441 0, /* tp_as_mapping*/
444 (reprfunc
)MessageInfo_str
, /* tp_str*/
448 Py_TPFLAGS_DEFAULT
, /* tp_flags*/
449 "A MessageInfo represents" /* tp_doc */
450 " a single message.\n\n"
451 "Do not construct objects of this type yourself.",
454 0, /* tp_richcompare */
455 0, /* tp_weaklistoffset */
458 MessageInfo_methods
, /* tp_methods */
460 MessageInfo_getset
, /* tp_getset */
463 0, /* tp_descr_get */
464 0, /* tp_descr_set */
465 0, /* tp_dictoffset */
466 (initproc
)MessageInfo_init
,/* tp_init */
474 0, /* tp_subclasses */
477 #if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6) || \
478 (PY_MAJOR_VERSION == 3))
479 0, /* tp_version_tag */
481 #if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4)
486 gboolean
cmpy_add_messageinfo(PyObject
*module
)
488 clawsmail_MessageInfoType
.tp_new
= PyType_GenericNew
;
489 if(PyType_Ready(&clawsmail_MessageInfoType
) < 0)
492 Py_INCREF(&clawsmail_MessageInfoType
);
493 return (PyModule_AddObject(module
, "MessageInfo", (PyObject
*)&clawsmail_MessageInfoType
) == 0);
496 PyObject
* clawsmail_messageinfo_new(MsgInfo
*msginfo
)
498 clawsmail_MessageInfoObject
*ff
;
503 ff
= (clawsmail_MessageInfoObject
*) PyObject_CallObject((PyObject
*) &clawsmail_MessageInfoType
, NULL
);
507 ff
->msginfo
= msginfo
;
508 return (PyObject
*)ff
;
511 PyTypeObject
* clawsmail_messageinfo_get_type_object()
513 return &clawsmail_MessageInfoType
;
516 MsgInfo
* clawsmail_messageinfo_get_msginfo(PyObject
*self
)
518 return ((clawsmail_MessageInfoObject
*)self
)->msginfo
;