fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / scripting / source / pyprov / mailmerge.py
blobc8867aa796d1fa96faae56a6e3b3a4dd6bedf26e
1 # Caolan McNamara caolanm@redhat.com
2 # a simple email mailmerge component
4 # manual installation for hackers, not necessary for users
5 # cp mailmerge.py /usr/lib/libreoffice/program
6 # cd /usr/lib/libreoffice/program
7 # ./unopkg add --shared mailmerge.py
8 # edit ~/.openoffice.org2/user/registry/data/org/openoffice/Office/Writer.xcu
9 # and change EMailSupported to as follows...
10 # <prop oor:name="EMailSupported" oor:type="xs:boolean">
11 # <value>true</value>
12 # </prop>
14 from __future__ import print_function
16 import unohelper
17 import uno
18 import re
19 import os
21 #to implement com::sun::star::mail::XMailServiceProvider
22 #and
23 #to implement com.sun.star.mail.XMailMessage
25 from com.sun.star.mail import XMailServiceProvider
26 from com.sun.star.mail import XMailService
27 from com.sun.star.mail import XSmtpService
28 from com.sun.star.mail import XConnectionListener
29 from com.sun.star.mail import XAuthenticator
30 from com.sun.star.mail import XMailMessage
31 from com.sun.star.mail.MailServiceType import SMTP
32 from com.sun.star.mail.MailServiceType import POP3
33 from com.sun.star.mail.MailServiceType import IMAP
34 from com.sun.star.uno import XCurrentContext
35 from com.sun.star.lang import IllegalArgumentException
36 from com.sun.star.lang import EventObject
37 from com.sun.star.lang import XServiceInfo
38 from com.sun.star.mail import SendMailMessageFailedException
40 from email.mime.base import MIMEBase
41 from email.message import Message
42 from email.charset import Charset
43 from email.charset import QP
44 from email.encoders import encode_base64
45 from email.header import Header
46 from email.mime.multipart import MIMEMultipart
47 from email.utils import formatdate
48 from email.utils import parseaddr
49 from socket import _GLOBAL_DEFAULT_TIMEOUT
51 import sys, smtplib, imaplib, poplib
52 dbg = False
54 # pythonloader looks for a static g_ImplementationHelper variable
55 g_ImplementationHelper = unohelper.ImplementationHelper()
56 g_providerImplName = "org.openoffice.pyuno.MailServiceProvider"
57 g_messageImplName = "org.openoffice.pyuno.MailMessage"
59 #no stderr under windows, output to pymailmerge.log
60 #with no buffering
61 if dbg and os.name == 'nt':
62 dbgout = open('pymailmerge.log', 'w', 0)
63 else:
64 dbgout = sys.stderr
66 class PyMailSMTPService(unohelper.Base, XSmtpService):
67 def __init__( self, ctx ):
68 self.ctx = ctx
69 self.listeners = []
70 self.supportedtypes = ('Insecure', 'Ssl')
71 self.server = None
72 self.connectioncontext = None
73 self.notify = EventObject(self)
74 if dbg:
75 print("PyMailSMTPService init", file=dbgout)
76 print("python version is: " + sys.version, file=dbgout)
77 def addConnectionListener(self, xListener):
78 if dbg:
79 print("PyMailSMTPService addConnectionListener", file=dbgout)
80 self.listeners.append(xListener)
81 def removeConnectionListener(self, xListener):
82 if dbg:
83 print("PyMailSMTPService removeConnectionListener", file=dbgout)
84 self.listeners.remove(xListener)
85 def getSupportedConnectionTypes(self):
86 if dbg:
87 print("PyMailSMTPService getSupportedConnectionTypes", file=dbgout)
88 return self.supportedtypes
89 def connect(self, xConnectionContext, xAuthenticator):
90 self.connectioncontext = xConnectionContext
91 if dbg:
92 print("PyMailSMTPService connect", file=dbgout)
93 server = xConnectionContext.getValueByName("ServerName")
94 if dbg:
95 print("ServerName: " + server, file=dbgout)
96 port = int(xConnectionContext.getValueByName("Port"))
97 if dbg:
98 print("Port: " + str(port), file=dbgout)
99 tout = xConnectionContext.getValueByName("Timeout")
100 if dbg:
101 print(isinstance(tout,int), file=dbgout)
102 if not isinstance(tout,int):
103 tout = _GLOBAL_DEFAULT_TIMEOUT
104 if dbg:
105 print("Timeout: " + str(tout), file=dbgout)
106 self.server = smtplib.SMTP(server, port,timeout=tout)
108 #stderr not available for us under windows, but
109 #set_debuglevel outputs there, and so throw
110 #an exception under windows on debugging mode
111 #with this enabled
112 if dbg and os.name != 'nt':
113 self.server.set_debuglevel(1)
115 connectiontype = xConnectionContext.getValueByName("ConnectionType")
116 if dbg:
117 print("ConnectionType: " + connectiontype, file=dbgout)
118 if connectiontype.upper() == 'SSL':
119 self.server.ehlo()
120 self.server.starttls()
121 self.server.ehlo()
123 user = xAuthenticator.getUserName()
124 password = xAuthenticator.getPassword()
125 if user != '':
126 if sys.version < '3': # fdo#59249 i#105669 Python 2 needs "ascii"
127 user = user.encode('ascii')
128 password = password.encode('ascii')
129 if dbg:
130 print("Logging in, username of: " + user, file=dbgout)
131 self.server.login(user, password)
133 for listener in self.listeners:
134 listener.connected(self.notify)
135 def disconnect(self):
136 if dbg:
137 print("PyMailSMTPService disconnect", file=dbgout)
138 if self.server:
139 self.server.quit()
140 self.server = None
141 for listener in self.listeners:
142 listener.disconnected(self.notify)
143 def isConnected(self):
144 if dbg:
145 print("PyMailSMTPService isConnected", file=dbgout)
146 return self.server != None
147 def getCurrentConnectionContext(self):
148 if dbg:
149 print("PyMailSMTPService getCurrentConnectionContext", file=dbgout)
150 return self.connectioncontext
151 def sendMailMessage(self, xMailMessage):
152 COMMASPACE = ', '
154 if dbg:
155 print("PyMailSMTPService sendMailMessage", file=dbgout)
156 recipients = xMailMessage.getRecipients()
157 sendermail = xMailMessage.SenderAddress
158 sendername = xMailMessage.SenderName
159 subject = xMailMessage.Subject
160 ccrecipients = xMailMessage.getCcRecipients()
161 bccrecipients = xMailMessage.getBccRecipients()
162 if dbg:
163 print("PyMailSMTPService subject: " + subject, file=dbgout)
164 print("PyMailSMTPService from: " + sendername, file=dbgout)
165 print("PyMailSMTPService from: " + sendermail, file=dbgout)
166 print("PyMailSMTPService send to: %s" % (recipients,), file=dbgout)
168 attachments = xMailMessage.getAttachments()
170 textmsg = Message()
172 content = xMailMessage.Body
173 flavors = content.getTransferDataFlavors()
174 if dbg:
175 print("PyMailSMTPService flavors len: %d" % (len(flavors),), file=dbgout)
177 #Use first flavor that's sane for an email body
178 for flavor in flavors:
179 if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find('text/plain') != -1:
180 if dbg:
181 print("PyMailSMTPService mimetype is: " + flavor.MimeType, file=dbgout)
182 textbody = content.getTransferData(flavor)
184 if len(textbody):
185 mimeEncoding = re.sub("charset=.*", "charset=UTF-8", flavor.MimeType)
186 if mimeEncoding.find('charset=UTF-8') == -1:
187 mimeEncoding = mimeEncoding + "; charset=UTF-8"
188 textmsg['Content-Type'] = mimeEncoding
189 textmsg['MIME-Version'] = '1.0'
191 try:
192 #it's a string, get it as utf-8 bytes
193 textbody = textbody.encode('utf-8')
194 except:
195 #it's a bytesequence, get raw bytes
196 textbody = textbody.value
197 if sys.version >= '3':
198 if sys.version_info.minor < 3 or (sys.version_info.minor == 3 and sys.version_info.micro <= 1):
199 #http://stackoverflow.com/questions/9403265/how-do-i-use-python-3-2-email-module-to-send-unicode-messages-encoded-in-utf-8-w
200 #see http://bugs.python.org/16564, etc. basically it now *seems* to be all ok
201 #in python 3.3.2 onwards, but a little busted in 3.3.0
203 textbody = textbody.decode('iso8859-1')
204 else:
205 textbody = textbody.decode('utf-8')
206 c = Charset('utf-8')
207 c.body_encoding = QP
208 textmsg.set_payload(textbody, c)
209 else:
210 textmsg.set_payload(textbody)
212 break
214 if (len(attachments)):
215 msg = MIMEMultipart()
216 msg.epilogue = ''
217 msg.attach(textmsg)
218 else:
219 msg = textmsg
221 hdr = Header(sendername, 'utf-8')
222 hdr.append('<'+sendermail+'>','us-ascii')
223 msg['Subject'] = subject
224 msg['From'] = hdr
225 msg['To'] = COMMASPACE.join(recipients)
226 if len(ccrecipients):
227 msg['Cc'] = COMMASPACE.join(ccrecipients)
228 if xMailMessage.ReplyToAddress != '':
229 msg['Reply-To'] = xMailMessage.ReplyToAddress
231 mailerstring = "LibreOffice via Caolan's mailmerge component"
232 try:
233 ctx = uno.getComponentContext()
234 aConfigProvider = ctx.ServiceManager.createInstance("com.sun.star.configuration.ConfigurationProvider")
235 prop = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
236 prop.Name = "nodepath"
237 prop.Value = "/org.openoffice.Setup/Product"
238 aSettings = aConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess",
239 (prop,))
240 mailerstring = aSettings.getByName("ooName") + " " + \
241 aSettings.getByName("ooSetupVersion") + " via Caolan's mailmerge component"
242 except:
243 pass
245 msg['X-Mailer'] = mailerstring
246 msg['Date'] = formatdate(localtime=True)
248 for attachment in attachments:
249 content = attachment.Data
250 flavors = content.getTransferDataFlavors()
251 flavor = flavors[0]
252 ctype = flavor.MimeType
253 maintype, subtype = ctype.split('/', 1)
254 msgattachment = MIMEBase(maintype, subtype)
255 data = content.getTransferData(flavor)
256 msgattachment.set_payload(data.value)
257 encode_base64(msgattachment)
258 fname = attachment.ReadableName
259 try:
260 msgattachment.add_header('Content-Disposition', 'attachment', \
261 filename=fname)
262 except:
263 msgattachment.add_header('Content-Disposition', 'attachment', \
264 filename=('utf-8','',fname))
265 if dbg:
266 print(("PyMailSMTPService attachmentheader: ", str(msgattachment)), file=dbgout)
268 msg.attach(msgattachment)
270 uniquer = {}
271 for key in recipients:
272 uniquer[key] = True
273 if len(ccrecipients):
274 for key in ccrecipients:
275 uniquer[key] = True
276 if len(bccrecipients):
277 for key in bccrecipients:
278 uniquer[key] = True
279 truerecipients = uniquer.keys()
281 if dbg:
282 print(("PyMailSMTPService recipients are: ", truerecipients), file=dbgout)
284 self.server.sendmail(sendermail, truerecipients, msg.as_string())
286 class PyMailIMAPService(unohelper.Base, XMailService):
287 def __init__( self, ctx ):
288 self.ctx = ctx
289 self.listeners = []
290 self.supportedtypes = ('Insecure', 'Ssl')
291 self.server = None
292 self.connectioncontext = None
293 self.notify = EventObject(self)
294 if dbg:
295 print("PyMailIMAPService init", file=dbgout)
296 def addConnectionListener(self, xListener):
297 if dbg:
298 print("PyMailIMAPService addConnectionListener", file=dbgout)
299 self.listeners.append(xListener)
300 def removeConnectionListener(self, xListener):
301 if dbg:
302 print("PyMailIMAPService removeConnectionListener", file=dbgout)
303 self.listeners.remove(xListener)
304 def getSupportedConnectionTypes(self):
305 if dbg:
306 print("PyMailIMAPService getSupportedConnectionTypes", file=dbgout)
307 return self.supportedtypes
308 def connect(self, xConnectionContext, xAuthenticator):
309 if dbg:
310 print("PyMailIMAPService connect", file=dbgout)
312 self.connectioncontext = xConnectionContext
313 server = xConnectionContext.getValueByName("ServerName")
314 if dbg:
315 print(server, file=dbgout)
316 port = int(xConnectionContext.getValueByName("Port"))
317 if dbg:
318 print(port, file=dbgout)
319 connectiontype = xConnectionContext.getValueByName("ConnectionType")
320 if dbg:
321 print(connectiontype, file=dbgout)
322 print("BEFORE", file=dbgout)
323 if connectiontype.upper() == 'SSL':
324 self.server = imaplib.IMAP4_SSL(server, port)
325 else:
326 self.server = imaplib.IMAP4(server, port)
327 print("AFTER", file=dbgout)
329 user = xAuthenticator.getUserName()
330 password = xAuthenticator.getPassword()
331 if user != '':
332 if sys.version < '3': # fdo#59249 i#105669 Python 2 needs "ascii"
333 user = user.encode('ascii')
334 password = password.encode('ascii')
335 if dbg:
336 print("Logging in, username of: " + user, file=dbgout)
337 self.server.login(user, password)
339 for listener in self.listeners:
340 listener.connected(self.notify)
341 def disconnect(self):
342 if dbg:
343 print("PyMailIMAPService disconnect", file=dbgout)
344 if self.server:
345 self.server.logout()
346 self.server = None
347 for listener in self.listeners:
348 listener.disconnected(self.notify)
349 def isConnected(self):
350 if dbg:
351 print("PyMailIMAPService isConnected", file=dbgout)
352 return self.server != None
353 def getCurrentConnectionContext(self):
354 if dbg:
355 print("PyMailIMAPService getCurrentConnectionContext", file=dbgout)
356 return self.connectioncontext
358 class PyMailPOP3Service(unohelper.Base, XMailService):
359 def __init__( self, ctx ):
360 self.ctx = ctx
361 self.listeners = []
362 self.supportedtypes = ('Insecure', 'Ssl')
363 self.server = None
364 self.connectioncontext = None
365 self.notify = EventObject(self)
366 if dbg:
367 print("PyMailPOP3Service init", file=dbgout)
368 def addConnectionListener(self, xListener):
369 if dbg:
370 print("PyMailPOP3Service addConnectionListener", file=dbgout)
371 self.listeners.append(xListener)
372 def removeConnectionListener(self, xListener):
373 if dbg:
374 print("PyMailPOP3Service removeConnectionListener", file=dbgout)
375 self.listeners.remove(xListener)
376 def getSupportedConnectionTypes(self):
377 if dbg:
378 print("PyMailPOP3Service getSupportedConnectionTypes", file=dbgout)
379 return self.supportedtypes
380 def connect(self, xConnectionContext, xAuthenticator):
381 if dbg:
382 print("PyMailPOP3Service connect", file=dbgout)
384 self.connectioncontext = xConnectionContext
385 server = xConnectionContext.getValueByName("ServerName")
386 if dbg:
387 print(server, file=dbgout)
388 port = int(xConnectionContext.getValueByName("Port"))
389 if dbg:
390 print(port, file=dbgout)
391 connectiontype = xConnectionContext.getValueByName("ConnectionType")
392 if dbg:
393 print(connectiontype, file=dbgout)
394 print("BEFORE", file=dbgout)
395 if connectiontype.upper() == 'SSL':
396 self.server = poplib.POP3_SSL(server, port)
397 else:
398 tout = xConnectionContext.getValueByName("Timeout")
399 if dbg:
400 print(isinstance(tout,int), file=dbgout)
401 if not isinstance(tout,int):
402 tout = _GLOBAL_DEFAULT_TIMEOUT
403 if dbg:
404 print("Timeout: " + str(tout), file=dbgout)
405 self.server = poplib.POP3(server, port, timeout=tout)
406 print("AFTER", file=dbgout)
408 user = xAuthenticator.getUserName()
409 password = xAuthenticator.getPassword()
410 if sys.version < '3': # fdo#59249 i#105669 Python 2 needs "ascii"
411 user = user.encode('ascii')
412 password = password.encode('ascii')
413 if dbg:
414 print("Logging in, username of: " + user, file=dbgout)
415 self.server.user(user)
416 self.server.pass_(password)
418 for listener in self.listeners:
419 listener.connected(self.notify)
420 def disconnect(self):
421 if dbg:
422 print("PyMailPOP3Service disconnect", file=dbgout)
423 if self.server:
424 self.server.quit()
425 self.server = None
426 for listener in self.listeners:
427 listener.disconnected(self.notify)
428 def isConnected(self):
429 if dbg:
430 print("PyMailPOP3Service isConnected", file=dbgout)
431 return self.server != None
432 def getCurrentConnectionContext(self):
433 if dbg:
434 print("PyMailPOP3Service getCurrentConnectionContext", file=dbgout)
435 return self.connectioncontext
437 class PyMailServiceProvider(unohelper.Base, XMailServiceProvider, XServiceInfo):
438 def __init__( self, ctx ):
439 if dbg:
440 print("PyMailServiceProvider init", file=dbgout)
441 self.ctx = ctx
442 def create(self, aType):
443 if dbg:
444 print("PyMailServiceProvider create with", aType, file=dbgout)
445 if aType == SMTP:
446 return PyMailSMTPService(self.ctx);
447 elif aType == POP3:
448 return PyMailPOP3Service(self.ctx);
449 elif aType == IMAP:
450 return PyMailIMAPService(self.ctx);
451 else:
452 print("PyMailServiceProvider, unknown TYPE " + aType, file=dbgout)
454 def getImplementationName(self):
455 return g_providerImplName
457 def supportsService(self, ServiceName):
458 return g_ImplementationHelper.supportsService(g_providerImplName, ServiceName)
460 def getSupportedServiceNames(self):
461 return g_ImplementationHelper.getSupportedServiceNames(g_providerImplName)
463 class PyMailMessage(unohelper.Base, XMailMessage):
464 def __init__( self, ctx, sTo='', sFrom='', Subject='', Body=None, aMailAttachment=None ):
465 if dbg:
466 print("PyMailMessage init", file=dbgout)
467 self.ctx = ctx
469 self.recipients = [sTo]
470 self.ccrecipients = []
471 self.bccrecipients = []
472 self.aMailAttachments = []
473 if aMailAttachment != None:
474 self.aMailAttachments.append(aMailAttachment)
476 self.SenderName, self.SenderAddress = parseaddr(sFrom)
477 self.ReplyToAddress = sFrom
478 self.Subject = Subject
479 self.Body = Body
480 if dbg:
481 print("post PyMailMessage init", file=dbgout)
482 def addRecipient( self, recipient ):
483 if dbg:
484 print("PyMailMessage.addRecipient: " + recipient, file=dbgout)
485 self.recipients.append(recipient)
486 def addCcRecipient( self, ccrecipient ):
487 if dbg:
488 print("PyMailMessage.addCcRecipient: " + ccrecipient, file=dbgout)
489 self.ccrecipients.append(ccrecipient)
490 def addBccRecipient( self, bccrecipient ):
491 if dbg:
492 print("PyMailMessage.addBccRecipient: " + bccrecipient, file=dbgout)
493 self.bccrecipients.append(bccrecipient)
494 def getRecipients( self ):
495 if dbg:
496 print("PyMailMessage.getRecipients: " + str(self.recipients), file=dbgout)
497 return tuple(self.recipients)
498 def getCcRecipients( self ):
499 if dbg:
500 print("PyMailMessage.getCcRecipients: " + str(self.ccrecipients), file=dbgout)
501 return tuple(self.ccrecipients)
502 def getBccRecipients( self ):
503 if dbg:
504 print("PyMailMessage.getBccRecipients: " + str(self.bccrecipients), file=dbgout)
505 return tuple(self.bccrecipients)
506 def addAttachment( self, aMailAttachment ):
507 if dbg:
508 print("PyMailMessage.addAttachment", file=dbgout)
509 self.aMailAttachments.append(aMailAttachment)
510 def getAttachments( self ):
511 if dbg:
512 print("PyMailMessage.getAttachments", file=dbgout)
513 return tuple(self.aMailAttachments)
515 def getImplementationName(self):
516 return g_messageImplName
518 def supportsService(self, ServiceName):
519 return g_ImplementationHelper.supportsService(g_messageImplName, ServiceName)
521 def getSupportedServiceNames(self):
522 return g_ImplementationHelper.getSupportedServiceNames(g_messageImplName)
524 g_ImplementationHelper.addImplementation( \
525 PyMailServiceProvider, g_providerImplName,
526 ("com.sun.star.mail.MailServiceProvider",),)
527 g_ImplementationHelper.addImplementation( \
528 PyMailMessage, g_messageImplName,
529 ("com.sun.star.mail.MailMessage",),)