p≡p for Python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
12 KiB

3 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
2 years ago
2 years ago
2 years ago
2 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. // This file is under GNU Affero General Public License 3.0
  2. // see LICENSE.txt
  3. #include <Python.h>
  4. #include "message.hh"
  5. #include "message_api.hh"
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <stdexcept>
  9. #include <sstream>
  10. #include <vector>
  11. #include <pEp/mime.h>
  12. #include <pEp/keymanagement.h>
  13. #include <pEp/message_api.h>
  14. namespace pEp {
  15. namespace PythonAdapter {
  16. using namespace std;
  17. Message::Blob::Blob(bloblist_t *bl, bool chained) :
  18. _bl(bl), part_of_chain(chained)
  19. {
  20. if (!_bl)
  21. throw bad_alloc();
  22. }
  23. Message::Blob::Blob(object data, string mime_type, string filename) :
  24. _bl(new_bloblist(NULL, 0, NULL, NULL)), part_of_chain(false)
  25. {
  26. if (!_bl)
  27. throw bad_alloc();
  28. Py_buffer src;
  29. int result = PyObject_GetBuffer(data.ptr(), &src, PyBUF_CONTIG_RO);
  30. if (result)
  31. throw invalid_argument("need a contiguous buffer to read");
  32. char *mem = (char *)malloc(src.len);
  33. if (!mem) {
  34. PyBuffer_Release(&src);
  35. throw bad_alloc();
  36. }
  37. memcpy(mem, src.buf, src.len);
  38. free(_bl->value);
  39. _bl->size = src.len;
  40. _bl->value = mem;
  41. PyBuffer_Release(&src);
  42. this->mime_type(mime_type);
  43. this->filename(filename);
  44. }
  45. Message::Blob::Blob(const Message::Blob& second) :
  46. _bl(second._bl), part_of_chain(true)
  47. {
  48. }
  49. Message::Blob::~Blob()
  50. {
  51. if (!part_of_chain) {
  52. free(_bl->value);
  53. free(_bl);
  54. }
  55. }
  56. string Message::Blob::_repr()
  57. {
  58. stringstream build;
  59. build << "Blob(";
  60. if (!_bl) {
  61. build << "b'', '', ''";
  62. }
  63. else {
  64. build << "bytes(" << _bl->size << "), ";
  65. string mime_type;
  66. if (_bl->mime_type)
  67. mime_type = string(_bl->mime_type);
  68. string filename;
  69. if (_bl->filename)
  70. filename = string(_bl->filename);
  71. build << repr(mime_type) << ", ";
  72. build << repr(filename);
  73. }
  74. build << ")";
  75. return build.str();
  76. }
  77. int Message::Blob::getbuffer(PyObject *self, Py_buffer *view, int flags) {
  78. bloblist_t *bl = NULL;
  79. try {
  80. Message::Blob& blob = extract< Message::Blob& >(self);
  81. bl = blob._bl;
  82. }
  83. catch (exception& e) {
  84. PyErr_SetString(PyExc_RuntimeError, "extract not possible");
  85. view->obj = NULL;
  86. return -1;
  87. }
  88. if (!(bl && bl->value)) {
  89. PyErr_SetString(PyExc_RuntimeError, "no data available");
  90. view->obj = NULL;
  91. return -1;
  92. }
  93. return PyBuffer_FillInfo(view, self, bl->value, bl->size, 0, flags);
  94. }
  95. string Message::Blob::decode(string encoding)
  96. {
  97. if (encoding == "") {
  98. string _mime_type = _bl->mime_type ? _bl->mime_type : "";
  99. encoding = "ascii";
  100. if (_mime_type == "application/pEp.sync")
  101. encoding = "pep.sync";
  102. if (_mime_type == "application/pEp.keyreset")
  103. encoding = "pep.distribution";
  104. }
  105. object codecs = import("codecs");
  106. object _decode = codecs.attr("decode");
  107. return call< string >(_decode.ptr(), this, encoding);
  108. }
  109. PyBufferProcs Message::Blob::bp = { getbuffer, NULL };
  110. Message::Message(int dir, Identity *from)
  111. : _msg(new_message((PEP_msg_direction) dir), &free_message)
  112. {
  113. if (!_msg)
  114. throw bad_alloc();
  115. if (from) {
  116. _msg->from = ::identity_dup(*from);
  117. if (!_msg->from)
  118. throw bad_alloc();
  119. _msg->dir = (PEP_msg_direction) dir;
  120. }
  121. }
  122. Message::Message(string mimetext)
  123. : _msg(NULL, &free_message)
  124. {
  125. message *_cpy;
  126. PEP_STATUS status = mime_decode_message(mimetext.c_str(),
  127. mimetext.size(), &_cpy, NULL);
  128. switch (status) {
  129. case PEP_STATUS_OK:
  130. if (_cpy)
  131. _cpy->dir = PEP_dir_outgoing;
  132. else
  133. _cpy = new_message(PEP_dir_outgoing);
  134. if (!_cpy)
  135. throw bad_alloc();
  136. _msg = shared_ptr< message >(_cpy);
  137. break;
  138. case PEP_BUFFER_TOO_SMALL:
  139. throw runtime_error("mime_decode_message: buffer too small");
  140. case PEP_CANNOT_CREATE_TEMP_FILE:
  141. throw runtime_error("mime_decode_message: cannot create temp file");
  142. case PEP_OUT_OF_MEMORY:
  143. throw bad_alloc();
  144. default:
  145. stringstream build;
  146. build << "mime_decode_message: unknown error (" << (int) status << ")";
  147. throw runtime_error(build.str());
  148. }
  149. }
  150. Message::Message(const Message& second)
  151. : _msg(second._msg)
  152. {
  153. if (!_msg.get())
  154. throw bad_alloc();
  155. }
  156. Message::Message(message *msg)
  157. : _msg(::message_dup(msg), &free_message)
  158. {
  159. }
  160. Message::~Message()
  161. {
  162. }
  163. Message::operator message *()
  164. {
  165. return _msg.get();
  166. }
  167. Message::operator const message *() const
  168. {
  169. return _msg.get();
  170. }
  171. string Message::_str()
  172. {
  173. if (!(_msg->from && _msg->from->address && _msg->from->address[0]))
  174. throw out_of_range(".from_.address missing");
  175. char *mimetext;
  176. string result;
  177. PEP_STATUS status = mime_encode_message(*this, false, &mimetext, false);
  178. switch (status) {
  179. case PEP_STATUS_OK:
  180. result = mimetext;
  181. free(mimetext);
  182. break;
  183. case PEP_BUFFER_TOO_SMALL:
  184. throw runtime_error("mime_encode_message: buffer too small");
  185. case PEP_CANNOT_CREATE_TEMP_FILE:
  186. throw runtime_error("mime_encode_message: cannot create temp file");
  187. case PEP_OUT_OF_MEMORY:
  188. throw bad_alloc();
  189. default:
  190. stringstream build;
  191. build << "mime_encode_message: unknown error (" << (int) status << ")";
  192. throw runtime_error(build.str());
  193. }
  194. return result;
  195. }
  196. string Message::_repr()
  197. {
  198. stringstream build;
  199. build << "Message(" << repr(_str()) << ")";
  200. return build.str();
  201. }
  202. boost::python::tuple Message::attachments()
  203. {
  204. boost::python::list l;
  205. for (bloblist_t *bl = _msg->attachments; bl && bl->value; bl =
  206. bl->next) {
  207. l.append(Blob(bl, true));
  208. }
  209. return boost::python::tuple(l);
  210. }
  211. void Message::attachments(boost::python::list value)
  212. {
  213. bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL);
  214. if (!bl)
  215. throw bad_alloc();
  216. bloblist_t *_l = bl;
  217. for (int i=0; i<len(value); i++) {
  218. Message::Blob& blob = extract< Message::Blob& >(value[i]);
  219. _l = bloblist_add(_l, blob._bl->value, blob._bl->size,
  220. blob._bl->mime_type, blob._bl->filename);
  221. if (!_l) {
  222. for (_l = bl; _l && _l->value; ) {
  223. free(_l->mime_type);
  224. free(_l->filename);
  225. bloblist_t *_ll = _l;
  226. _l = _l->next;
  227. free(_ll);
  228. }
  229. throw bad_alloc();
  230. }
  231. }
  232. for (int i=0; i<len(value); i++) {
  233. Message::Blob& blob = extract< Message::Blob& >(value[i]);
  234. blob._bl->value = NULL;
  235. blob._bl->size = 0;
  236. free(blob._bl->mime_type);
  237. blob._bl->mime_type = NULL;
  238. free(blob._bl->filename);
  239. blob._bl->filename = NULL;
  240. }
  241. free_bloblist(_msg->attachments);
  242. _msg->attachments = bl;
  243. }
  244. Message Message::encrypt()
  245. {
  246. boost::python::list extra;
  247. return encrypt_message(*this, extra, PEP_enc_PGP_MIME, 0);
  248. }
  249. Message Message::_encrypt(boost::python::list extra, int enc_format, int flags)
  250. {
  251. if (!enc_format)
  252. enc_format = PEP_enc_PGP_MIME;
  253. return encrypt_message(*this, extra, enc_format, flags);
  254. }
  255. boost::python::tuple Message::decrypt(int flags) {
  256. return pEp::PythonAdapter::decrypt_message(*this, flags);
  257. }
  258. PEP_rating Message::outgoing_rating()
  259. {
  260. if (_msg->dir != PEP_dir_outgoing)
  261. throw invalid_argument("Message.dir must be outgoing");
  262. if (from().address() == "")
  263. throw invalid_argument("from.address needed");
  264. if (from().username() == "")
  265. throw invalid_argument("from.username needed");
  266. if (len(to()) + len(cc()) == 0)
  267. throw invalid_argument("either to or cc needed");
  268. PEP_STATUS status = myself(adapter.session(), _msg->from);
  269. _throw_status(status);
  270. PEP_rating rating = PEP_rating_undefined;
  271. status = outgoing_message_rating(adapter.session(), *this, &rating);
  272. _throw_status(status);
  273. return rating;
  274. }
  275. PEP_color Message::outgoing_color()
  276. {
  277. return _color(outgoing_rating());
  278. }
  279. Message Message::copy()
  280. {
  281. message *dup = message_dup(*this);
  282. if (!dup)
  283. throw bad_alloc();
  284. return Message(dup);
  285. }
  286. Message Message::deepcopy(dict&)
  287. {
  288. return copy();
  289. }
  290. Message outgoing_message(Identity me)
  291. {
  292. if (me.address().empty() || me.user_id().empty())
  293. throw runtime_error("at least address and user_id of own user needed");
  294. ::myself(adapter.session(), me);
  295. auto m = Message(PEP_dir_outgoing, &me);
  296. return m;
  297. }
  298. static object update(Identity ident)
  299. {
  300. if (ident.address().empty())
  301. throw runtime_error("at least address needed");
  302. update_identity(adapter.session(), ident);
  303. return object(ident);
  304. }
  305. static boost::python::list update(boost::python::list il)
  306. {
  307. for (int i=0; i<len(il); i++) {
  308. update(extract< Identity >(il[i]));
  309. }
  310. return il;
  311. }
  312. Message incoming_message(string mime_text)
  313. {
  314. auto m = Message(mime_text);
  315. m.dir(PEP_dir_incoming);
  316. try {
  317. m.from(update(m.from()));
  318. }
  319. catch (out_of_range&) { }
  320. try {
  321. m.recv_by(update(m.recv_by()));
  322. }
  323. catch (out_of_range&) { }
  324. m.to(update(m.to()));
  325. m.cc(update(m.cc()));
  326. m.reply_to(update(m.reply_to()));
  327. return m;
  328. }
  329. }
  330. }