765cdf9ba8e7912c6c310258f6164557d05d8e8b
[vuplus_dvbapp-plugin] / emailclient / src / plugin.py
1 from Components.ActionMap import ActionMap
2 from Components.GUIComponent import GUIComponent
3 from Components.HTMLComponent import HTMLComponent
4 from Components.Label import Label
5 from Screens.MessageBox import MessageBox
6 from Components.MenuList import MenuList
7 from Components.MultiContent import MultiContentEntryText, MultiContentTemplateColor
8 from Components.ScrollLabel import ScrollLabel
9 from Components.Button import Button
10 from Components.config import config, ConfigSubsection, ConfigInteger, ConfigText, ConfigEnableDisable
11 from EmailConfig import EmailConfigScreen
12 from Plugins.Plugin import PluginDescriptor
13 from Screens.ChoiceBox import ChoiceBox
14 from Screens.Screen import Screen
15 from enigma import eListboxPythonMultiContent, eListbox, gFont
16 from twisted.mail import imap4
17 from zope.interface import implements
18 import email
19 import email.Parser
20 from email.header import decode_header
21 from TagStrip import strip_readable
22 from protocol import createFactory
23
24 config.plugins.emailimap = ConfigSubsection()
25 config.plugins.emailimap.username = ConfigText("user", fixed_size=False)
26 config.plugins.emailimap.password = ConfigText("password", fixed_size=False)
27 config.plugins.emailimap.server = ConfigText("please.config.first", fixed_size=False)
28 config.plugins.emailimap.port = ConfigInteger(143, limits = (1, 65536))
29 config.plugins.emailimap.showDeleted = ConfigEnableDisable(default=False)
30
31 # 0= fetch all header , 10= fetch only the last 10 headers/messages of a mailbox
32 config.plugins.emailimap.maxheadertoload = ConfigInteger(0, limits = (1, 100))
33
34 from enigma import getDesktop
35 DESKTOP_WIDTH = getDesktop(0).size().width()
36 DESKTOP_HEIGHT = getDesktop(0).size().height()
37 #
38 # this is pure magic.
39 # It returns the first value, if HD (1280x720),
40 # the second if SD (720x576),
41 # else something scaled accordingly
42 # if one of the parameters is -1, scale proportionally
43 #
44 def scaleH(y2, y1):
45         if y2 == -1:
46                 y2 = y1*1280/720
47         elif y1 == -1:
48                 y1 = y2*720/1280
49         return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
50 def scaleV(y2, y1):
51         if y2 == -1:
52                 y2 = y1*720/576
53         elif y1 == -1:
54                 y1 = y2*576/720
55         return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
56 def scale(y2, y1, x2, x1, x):
57         return (y2 - y1) * (x - x1) / (x2 - x1) + y1
58
59 def decodeHeader(text, default=''):
60         if text is None:
61                 return _(default)
62         text = text.replace('\r',' ').replace('\n',' ').replace('\t',' ')
63         while text.find('  ') != -1:
64                 text = text.replace('  ',' ')
65         textNew = ""
66         for part in decode_header(text):
67                 (content, charset) = part
68                 # print("decodeHeader content/charset: %s/%s" %(repr(content),charset))
69                 if charset:
70                         textNew += content.decode(charset)
71                 else:
72                         textNew += content
73         try:
74                 return textNew.encode('utf-8')
75         except: # for faulty mail software systems
76                 return textNew.decode('iso-8859-1').encode('utf-8')
77
78 IS_UNSEEN = 0
79 IS_SEEN = 1
80 IS_DELETED = 2 
81
82 class EmailHandler:
83         def __init__(self):
84                 pass
85         def onConnect(self, proto):
86                 pass
87
88 class EmailScreen(Screen, EmailHandler):
89         implements(imap4.IMailboxListener)
90
91         width = scaleH(-1,530)
92         height = scaleV(-1,430)
93         boxlistWidth = scaleH(-1,150)
94         messagelistWidth = width-boxlistWidth
95         infolabelHeight = scaleV(-1,30)
96         skin = """
97                 <screen position="%d,%d" size="%d,%d" title="Email" >
98                         <widget name="boxlist" position="0,0" size="%d,%d" scrollbarMode="showOnDemand" />
99                         <widget name="messagelist" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" />
100                         <widget name="infolabel" position="%d,%d" size="%d,%d"   foregroundColor=\"white\" font=\"Regular;%d\" />
101                 </screen>""" %(
102                                            (DESKTOP_WIDTH-width)/2, (DESKTOP_HEIGHT-height)/2, width, height,
103                                            boxlistWidth, height-infolabelHeight,
104                                            boxlistWidth, 0, messagelistWidth, height-infolabelHeight,
105                                            0, height-infolabelHeight, width, infolabelHeight, scaleV(20,18)
106                                            )
107
108         currentmailbox = None
109         proto = None
110
111         def __init__(self, session, args = 0):
112                 EmailHandler.__init__(self)
113                 self.session = session
114
115                 self.skin = EmailScreen.skin
116                 Screen.__init__(self, session)
117                 createFactory(self, config.plugins.emailimap.username.value, config.plugins.emailimap.server.value, config.plugins.emailimap.port.value)
118
119                 self["actions"] = ActionMap(["InfobarChannelSelection", "WizardActions", "DirectionActions", "MenuActions", "ShortcutActions", "GlobalActions", "HelpActions", "NumberActions", "ChannelSelectBaseActions"],
120                         {
121                          "ok": self.action_ok,
122                          "back": self.action_exit,
123                          "historyNext": self.selectMessagelist,
124                          "historyBack": self.selectBoxlist,
125                          "nextBouquet": self.selectMessagelist,
126                          "prevBouquet": self.selectBoxlist,
127                          "down":                self.down,
128                          "up":            self.up,
129                          "left":                self.left,
130                          "right":          self.right,
131                          "menu":                self.action_menu,
132                          }, -1)
133                 self["boxlist"] = MenuList([])
134                 self["messagelist"] = MailList([])
135                 self["infolabel"] = Label("")
136                 self.onLayoutFinish.append(self.selectBoxlist)
137
138         def action_menu(self):
139                 self.session.open(EmailConfigScreen).onHide.append(self.onBoxSelected)
140
141         def selectBoxlist(self):
142                 self.currList = "boxlist"
143                 self["boxlist"].selectionEnabled(1)
144                 self["messagelist"].selectionEnabled(0)
145
146         def selectMessagelist(self):
147                 self.currList = "messagelist"
148                 self["boxlist"].selectionEnabled(0)
149                 self["messagelist"].selectionEnabled(1)
150
151         def up(self):
152                 self[self.currList].up()
153
154         def down(self):
155                 self[self.currList].down()
156
157         def left(self):
158                 self[self.currList].pageUp()
159
160         def right(self):
161                 self[self.currList].pageDown()
162
163         def action_ok(self):
164                 if self.currList == "boxlist":
165                         self.onBoxSelected()
166                 else:
167                         self.onMessageSelected()
168
169         def onBoxSelected(self):
170                 c = self["boxlist"].getCurrent()
171                 if c is not None:
172                         self.proto.select(UTF7toUTF8(c[1][2]) # select instead of examine to get write access
173                                                            ).addCallback(self.onExamine, c[0] , self.proto
174                                                           ).addErrback(self.onExamineFailed, self.proto
175                                                           )
176
177         def onMessageSelected(self):
178                 c = self["messagelist"].getCurrent()
179                 if c is not None:
180                         self.fetchMessageSize(c[0])
181
182         def fetchMessageSize(self, message):
183                 print "fetchMessageSize",message
184                 self.proto.fetchSize(message.uid
185                         ).addCallback(self.onMessageSizeLoaded, message, self.proto
186                         ).addErrback(self.onMessageLoadFailed, message, self.proto
187                         )
188
189         def onMessageSizeLoaded(self, result, message, proto):
190                 print "onMessageSizeLoaded", result, message
191                 size = int(result[message.uid]['RFC822.SIZE'])
192                 self.MAX_MESSAGE_SIZE_TO_OPEN = 4000000
193                 if size >= self.MAX_MESSAGE_SIZE_TO_OPEN:
194                         #ask here to open message
195                         print "message to large to open (size=", size, ")"
196                 else:
197                         self.loadMessage(message)
198
199 #       def fetchBodyStructure(self, message):
200 #               print "fetchBodyStructure",message
201 #               self.proto.fetchBodyStructure(message.uid
202 #                       ).addCallback(self.onBodystructureLoaded, message, self.proto
203 #                       ).addErrback(self.onMessageLoadFailed, message, self.proto
204 #                       )
205
206         def loadMessage(self, message):
207                 print "loadMessage",message
208                 self["infolabel"].setText("loading message")
209
210                 self.proto.fetchMessage(message.uid
211                         ).addCallback(self.onMessageLoaded, message, self.proto
212                         ).addErrback(self.onMessageLoadFailed, message, self.proto
213                         )
214
215         def onMessageLoaded(self, result, message, proto):
216                 self["infolabel"].setText("parsing message")
217                 print "onMessageLoaded"#,result,message
218                 try:
219                         msgstr = result[message.uid]['RFC822']
220                 except KeyError:
221                         self.loadMessage(message)
222                         return
223                 msg = email.Parser.Parser().parsestr(msgstr)
224                 msg.messagebodys = []
225                 msg.attachments = []
226
227                 if msg.is_multipart():
228                         for part in msg.walk():
229                                 if part.get_content_maintype()=="multipart":
230                                         continue
231                                 if part.get_content_maintype() == 'text' and part.get_filename() is None:
232                                         if part.get_content_subtype() == "html":
233                                                 msg.messagebodys.append(EmailBody(part))
234                                         elif part.get_content_subtype() == "plain":
235                                                 msg.messagebodys.append(EmailBody(part))
236                                         else:
237                                                 print "unkown content type= ", part.get_content_maintype(), "/", part.get_content_subtype()
238                                 else:
239                                         print "found Attachment with  ", part.get_content_type(), "and name", part.get_filename()
240                                         msg.attachments.append(EmailAttachment(part.get_filename(), part.get_content_type(), part.get_payload()))
241                 else:
242                         msg.messagebodys.append(EmailBody(msg))
243                 self.session.open(ScreenMailView, msg, message.uid, proto, self.flagsList[message.uid]['FLAGS']).onHide.append(self.onBoxSelected)
244
245         def onMessageLoadFailed(self, failure, message, proto):
246                 print "onMessageLoadFailed", failure, message
247                 self["infolabel"].setText(failure.getErrorMessage())
248
249         def action_exit(self):
250                 if self.proto is not None:
251                         self.proto.logout().addCallback(self.onLogedOut, self.proto).addErrback(self.onLogedOut, self.proto)
252                 else:
253                         self.close()
254
255         def onLogedOut(self, result, proto):
256                 print "onLogedOut", result
257                 self.close()
258
259         def onConnect(self, proto):
260                 self["infolabel"].setText("connected")
261                 proto.getCapabilities(
262                                                 ).addCallback(self.cbCapabilities, proto
263                                                 ).addErrback(self.ebCapabilities, proto
264                                                 )
265
266         def cbCapabilities(self,reason,proto):
267                 print "#"*30
268                 print "# If you have problems to log into your imap-server, please send me the output of the following line"
269                 print "# cbCapabilities",reason
270                 print "#"*30
271                 self.doLogin(proto)
272
273         def ebCapabilities(self,reason,proto):
274                 print "ebCapabilities",reason
275
276         def onConnectFailed(self, reason):
277                 self["infolabel"].setText(reason.getErrorMessage())
278
279         def onAuthentication(self, result, proto):
280                 self.proto = proto
281                 self["infolabel"].setText("logged in")
282                 # better use LSUB here to get only the subscribed to mailboxes
283                 proto.lsub("", "*").addCallback(self.onMailboxList, proto)
284
285         def doLogin(self, proto):
286                 print "login secure"
287                 useTLS = False #True
288                 if useTLS:
289                         context = proto.context.getContext()
290                         d = proto.startTLS(context)
291                         d = d.addCallback(proto.authenticate, config.plugins.emailimap.password.value)
292                 else:
293                         d = proto.authenticate(config.plugins.emailimap.password.value)
294                 d.addCallback(self.onAuthentication, proto)
295                 d.addErrback(self.onAuthenticationFailed, proto)
296                 return d
297
298         def onAuthenticationFailed(self, failure, proto):
299                 # If it failed because no SASL mechanisms match
300                 print "onAuthenticationFailed", failure, proto
301                 self["infolabel"].setText(failure.getErrorMessage())
302                 try:
303                         failure.trap(imap4.NoSupportedAuthentication)
304                         self.doLoginInsecure(proto)
305                 except Exception,e:
306                         print e,e.message
307
308         def doLoginInsecure(self, proto):
309                 print "login INSECURE"
310                 proto.login(config.plugins.emailimap.username.value, config.plugins.emailimap.password.value
311                                 ).addCallback(self.onAuthentication, proto
312                                 ).addErrback(self.onInsecureAuthenticationFailed, proto
313                                 )
314
315         def onInsecureAuthenticationFailed(self, failure, proto):
316                 print "onInsecureAuthenticationFailed", failure, proto
317                 self["infolabel"].setText(failure.getErrorMessage())
318
319         def onMailboxList(self, result, proto):
320                 print "onMailboxList", result, proto
321                 list = []
322                 inboxPos = 0
323                 for i in result:
324                         flags, hierarchy_delimiter, name = i #@UnusedVariable
325                         list.append((UTF7toUTF8(name).encode('utf-8'), i))
326                         if name.lower() == 'inbox':
327                                 inboxPos = len(list)
328                 self["boxlist"].setList(list)
329                 self["boxlist"].moveToIndex(inboxPos-1)
330
331         def onExamine(self, result, mboxname, proto):
332                 print "onExamine", result, mboxname
333                 self.setTitle("Mailbox: "+mboxname)
334                 self.currentmailbox = mboxname
335                 numMessagesinFolder = int(result['EXISTS'])
336                 if numMessagesinFolder <= 0:
337                         self["infolabel"].setText("Box '"+mboxname+"' is empty")
338                         self["messagelist"].l.setList([])
339
340                 else:
341                         if config.plugins.emailimap.maxheadertoload.value > 0:
342                                 maxMessagesToFetch = config.plugins.emailimap.maxheadertoload.value
343                                 startmsg = numMessagesinFolder-maxMessagesToFetch+1
344                                 if startmsg <= 0:
345                                         startmsg = 1
346                                 rangeToFetch = [startmsg, numMessagesinFolder]
347                         else:
348                                 rangeToFetch = [1, numMessagesinFolder]
349                         self["infolabel"].setText("loading headers "+str(rangeToFetch[0])+"-"+str(rangeToFetch[1])+" of Box '"+mboxname+"'")
350
351                         try:
352 #                               proto.fetchEnvelope('%i:%i'%(rangeToFetch[0], rangeToFetch[1])  #'1:*'
353 #                                                  ).addCallback(self.onEnvelopeList, proto
354 #                                                  )
355                                 self.proto = proto
356                                 self.rangeToFetch = rangeToFetch
357                                 proto.fetchFlags('%i:%i'%(rangeToFetch[0], rangeToFetch[1])     #'1:*'
358                                                    ).addCallback(self.onFlagsList)
359
360                         except imap4.IllegalServerResponse, e:
361                                 print e
362                         self.selectMessagelist()
363
364         def onFlagsList(self, result):
365                 self.flagsList = result
366                 self.proto.fetchHeaders('%i:%i'%(self.rangeToFetch[0], self.rangeToFetch[1])    #'1:*'
367                                    ).addCallback(self.onHeaderList, self.proto
368                                    )
369
370         def onExamineFailed(self, failure, proto):
371                 print "onExamineFailed", failure, proto
372                 self["infolabel"].setText(failure.getErrorMessage())
373
374         def cbOk(self, result):
375                 print("cbOk result: %s" %repr(result))
376
377         def cbNotOk(self, result):
378                 print("cbNotOk result: %s" %(result))
379
380         def onHeaderList(self, result, proto):
381                 print "onHeaderList"#,result,proto
382                 self["infolabel"].setText("headers loaded, now parsing ...")
383                 list = []
384                 for m in result:
385                         state = IS_UNSEEN
386                         # print("onHeaderList :" + repr(self.flagsList[m]['FLAGS']))
387                         if '\\Seen' in self.flagsList[m]['FLAGS']:
388                                 state = IS_SEEN
389                         if '\\Deleted' in self.flagsList[m]['FLAGS']:
390                                 if not config.plugins.emailimap.showDeleted.value:
391                                         continue
392                                 else:
393                                         state = IS_DELETED
394                         try:
395                                 list.append(self.buildMessageListItem(MessageHeader(m, result[m]['RFC822.HEADER']), state))
396                         except Exception,e:
397                                 try:
398                                         list.append(self.buildMessageListItem(MessageHeader(m, result[m]['RFC822.HEADER'].decode('iso8859-1', 'replace'), state)))
399                                 except:
400                                         # this appear to be errors in the formatting of the mail itself...
401                                         print "onHeaderList error: %s with: %s" %(e,result[m]['RFC822.HEADER'])
402                 list.reverse()
403                 self["messagelist"].l.setList(list)
404                 self["infolabel"].setText("have "+str(len(list))+" messages ")
405
406         def buildMessageListItem(self, message, state):
407                 if state == IS_UNSEEN:
408                         font = 0
409                         color = 0x00FFFFFF # white
410                 elif state == IS_DELETED:
411                         font = 1 
412                         color = 0x00FF6666 # redish :)
413                 else:
414                         font = 2
415                         color = 0x00888888 # grey
416                 return [
417                         message,
418                         MultiContentEntryText(pos=(5, 0), size=(self.messagelistWidth, scaleV(20,18)+5), font=font, text=message.getSenderString(), color=color, color_sel=color),
419                         MultiContentEntryText(pos=(5, scaleV(20,18)+1), size=(self.messagelistWidth, scaleV(20,18)+5), font=font, text=message.get('date', default='kein Datum'), color=color, color_sel=color),
420                         MultiContentEntryText(pos=(5, 2*(scaleV(20,18)+1)), size=(self.messagelistWidth, scaleV(20,18)+5), font=font, text=message.getSubject(), color=color, color_sel=color)
421                 ]
422         #
423         # IMailboxListener methods
424         #
425         def modeChanged(self, writeable):
426                 print "modeChanged", writeable
427
428         def flagsChanged(self, newFlags):
429                 print "flagsChanged", newFlags
430
431         def newMessages(self, exists, recent):
432                 print "newMessages", exists, recent
433
434 class ScreenMailView(Screen):
435         skin=""
436         def __init__(self, session, email, uid, proto, flags):
437                 self.session = session
438                 self.email = email
439                 # print('ScreenMailView ' + repr(email) + ' dir: ' + repr(dir(email)))
440                 width = max(4*140,scaleH(-1,550))
441                 height = scaleV(-1,476)
442                 fontSize = scaleV(24,20)
443                 lineHeight = fontSize+5
444                 buttonsGap = (width-4*140)/5
445                 self.skin = """
446                 <screen position="%d,%d" size="%d,%d" title="view Email" >
447                         <widget name="from" position="%d,%d" size="%d,%d"  font="Regular;%d" />
448                         <widget name="date" position="%d,%d" size="%d,%d"  font="Regular;%d" />
449                         <widget name="subject" position="%d,%d" size="%d,%d"  font="Regular;%d" />
450                         <eLabel position="%d,%d" size="%d,2" backgroundColor="#aaaaaa" />
451                         <widget name="body" position="%d,%d" size="%d,%d"  font="Regular;%d" />
452                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
453                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
454                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
455                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
456                         <widget name="buttonred" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
457                         <widget name="buttongreen" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
458                         <widget name="buttonyellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
459                         <widget name="buttonblue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
460                 </screen>""" %(
461                                            (DESKTOP_WIDTH-width)/2, (DESKTOP_HEIGHT-height)/2, width, height,
462                                            0, 0, width, lineHeight, fontSize-1, # from
463                                            0, lineHeight, width, lineHeight, fontSize-1, # date
464                                            0, 2*lineHeight, width, lineHeight, fontSize-1, # subject 
465                                            0, 3*lineHeight+1, width, # line 
466                                            0, 3*lineHeight+5, width, height-3*lineHeight-5-5-30-5, fontSize, # body
467                                            buttonsGap, height-30-5,
468                        2*buttonsGap+140, height-30-5,
469                        3*buttonsGap+2*140, height-30-5,
470                        4*buttonsGap+3*140, height-30-5,
471                        buttonsGap, height-30-5, scaleV(18,16),
472                        2*buttonsGap+140, height-30-5, scaleV(18,16),
473                        3*buttonsGap+2*140, height-30-5, scaleV(18,16),
474                        4*buttonsGap+3*140, height-30-5, scaleV(18,16),
475                                            )
476                 Screen.__init__(self, session)
477                 self["from"] = Label(decodeHeader(_("From") +": %s" %self.email.get('from', 'no-from')))
478                 self["date"] = Label(_("Date") +": %s" %self.email.get('date', 'no-date'))
479                 self["subject"] = Label(decodeHeader(_("Subject") +": %s" %self.email.get('subject', 'no-subject')))
480                 self["body"] = ScrollLabel(_(self.email.messagebodys[0].getData()))
481                 # TODO: show headers
482                 self["buttonred"] = Button(_(""))
483                 self["buttongreen"] = Button("")
484                 self["buttonyellow"] = Button(_("leave unread"))
485                 if '\\Deleted' in flags:
486                         self["buttonblue"] = Button(_("undelete"))
487                 else:
488                         self["buttonblue"] = Button(_("delete"))
489                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "MenuActions", "ShortcutActions"],
490                         {
491                          "back": self.close,
492                          "up": self["body"].pageUp,
493                          "down": self["body"].pageDown,
494                          # TODO: perhaps better use left/right for previous/next message
495                          "left": self["body"].pageUp,
496                          "right": self["body"].pageDown,
497                          "red": self.selectBody,
498                          "green": self.selectAttachment,
499                          "yellow": self.markUnread,
500                          "blue": self.delete,
501
502                          }, -1)
503                 self.flags = flags
504                 self.proto = proto
505                 self.uid = uid
506                 proto.fetchFlags(self.uid).addCallback(self.cbOk).addErrback(self.cbNotOk)
507                 self.onLayoutFinish.append(self.updateButtons)
508
509         def cbOk(self, result):
510                 print("cbOk result: %s" %repr(result))
511
512         def cbNotOk(self, result):
513                 print("cbNotOk result: %s" %(result))
514
515         def delete(self):
516                 if '\\Deleted' in self.flags:
517                         self.session.openWithCallback(self.deleteCB, ChoiceBox, title=_("really undelete Mail?"), list=[(_("yes"), True),(_("no"), False)])
518                 else:
519                         self.session.openWithCallback(self.deleteCB, ChoiceBox, title=_("really delete Mail?"), list=[(_("yes"), True),(_("no"), False)])
520
521         def deleteCB(self, returnValue):
522                 if returnValue[1] is True:
523                         if '\\Deleted' in self.flags:
524                                 self.proto.removeFlags(self.uid, ["\\Deleted"]).addCallback(self.cbOk).addErrback(self.cbNotOk)
525                         else:
526                                 self.proto.addFlags(self.uid, ["\\Deleted"]).addCallback(self.cbOk).addErrback(self.cbNotOk)
527                         print("deleteCB: %s"  %repr(self.email))
528                         self.close()
529
530         def markUnread(self):
531                 self.proto.removeFlags(self.uid, ["\\Seen"]).addCallback(self.cbOk).addErrback(self.cbNotOk)
532                 self.close()
533
534         def openMessagesHeaders(self):
535                 pass #self.session.open(ScreenMailViewHeader,self.profil,self.email)
536
537         def updateButtons(self):
538                 self["buttonred"].setText(_("Bodys"))
539                 if len(self.email.attachments):
540                         self["buttongreen"].setText(_("Attachments"))
541                 else:
542                         self["buttongreen"].setText("")
543
544         def selectBody(self):
545                 if len(self.email.messagebodys):
546                         list = []
547                         for a in self.email.messagebodys:
548                                 list.append((a.getContenttype(), a))
549                         self.session.openWithCallback(self.selectBodyCB, ChoiceBox, _("select Body"), list)
550
551         def selectBodyCB(self, choice):
552                 if choice is not None:
553                         self["body"].setText(choice[1].getData())
554
555         def selectAttachment(self):
556                 if len(self.email.attachments):
557                         list = []
558                         for a in self.email.attachments:
559                                 name = a.getFilename()
560                                 if name:
561                                         list.append((a.getFilename(), a))
562                                 else:
563                                         list.append((_("no filename"), a))
564                         print("selectAttachment : " + repr(list))
565                         self.session.openWithCallback(self.selectAttachmentCB, ChoiceBox, _("select Attachment"), list)
566
567         def selectAttachmentCB(self, choice):
568                 if choice is not None:
569                         print "Attachment selected", choice[1].getFilename()
570                         #showMessageBox(self.session)
571
572 class MailList(MenuList):
573         def __init__(self, list, enableWrapAround = False):
574                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
575                 self.l.setFont(0, gFont("Regular", scaleV(20,18))) # new
576                 self.l.setFont(1, gFont("Regular", scaleV(18,16))) # deleted
577                 self.l.setFont(2, gFont("Regular", scaleV(18,16))) # seen
578
579         def postWidgetCreate(self, instance):
580                 MenuList.postWidgetCreate(self, instance)
581                 instance.setItemHeight(scaleV(70,60))
582
583 class MessageHeader(object):
584         def __init__(self, uid, message):
585                 self.uid = uid #must be int
586                 self.message = email.Parser.Parser().parsestr(message)
587
588         def getSenderString(self):
589                 return decodeHeader(self.get("from"), _("no sender"))
590
591         def getSubject(self):
592                 return decodeHeader(self.get("subject"), _("no subject"))
593
594         def get(self, key, default=None):
595                 return self.message.get(key,failobj=default)
596
597         def __str__(self):
598                 return "<MessageHeader uid="+str(self.uid)+", subject="+self.get("subject","no-subject")+">"
599
600 ############
601 class EmailBody:
602         def __init__(self,data):
603                 self.data = data
604
605         def getEncoding(self):
606                 return self.data.get_content_charset()
607
608         def getData(self):
609                 text = self.data.get_payload(decode=True)
610                 if self.getEncoding():
611                         try:
612                                 text = text.decode(self.getEncoding())
613                         except UnicodeDecodeError:
614                                 pass    
615                 # print('EmailBody/getData text: ' +  text)
616                 #=======================================================================
617                 # if self.getEncoding():
618                 #       text = text.decode(self.getEncoding())
619                 #=======================================================================
620                 if self.getContenttype() == "text/html":
621                         print "stripping html"
622                         text = strip_readable(text)
623                         # print('EmailBody/getData text: ' +  text)
624
625                 try:
626                         return text.encode('utf-8')
627                 except UnicodeDecodeError:
628                         return text
629                 
630
631         def getContenttype(self):
632                 return self.data.get_content_type()
633
634 ############
635 class EmailAttachment:
636         def __init__(self, filename, contenttype, data):
637                 self.filename = filename
638                 self.contenttype = contenttype
639                 self.data = data
640
641         def save(self,folder):
642                 try:
643                         fp = open(folder+"/"+self.getFilename(),"wb")
644                         fp.write(self.data)
645                         fp.close()
646                 except Exception,e:
647                         print e
648                         return False
649                 return True
650
651         def getFilename(self):
652                 return self.filename
653
654         def getContenttype(self):
655                 return self.contenttype
656
657         def getData(self):
658                 return self.data
659
660 def UTF7toUTF8(str):
661         return imap4.decoder(str)[0]
662
663 def UTF8toUTF7(str):
664         return imap4.encoder(str.decode('utf-8'))[0]
665
666 def main(session, **kwargs):
667         import os,shutil
668         if os.path.isfile('/usr/lib/python2.5/uu.py') is not True:
669                 shutil.copy('/usr/lib/enigma2/python/Plugins/Extensions/EmailClient/uu.py', '/usr/lib/python2.5/uu.py')
670                 global session2
671                 session2 = session
672                 session.openWithCallback(MessageCB, MessageBox, 'In order of missing standart python library files\ni have copied the nessary files now.\nBut you have to restart your Box\n to apply this!', type = MessageBox.TYPE_INFO)
673         else:
674                 session.open(EmailScreen)
675
676 def MessageCB(*args):
677         global session2
678         session2.open(EmailScreen)
679
680 def Plugins(path, **kwargs):
681         global plugin_path
682         plugin_path = path
683         return [
684                          PluginDescriptor(name="Email Client", description="view Emails via IMAP4",
685                          where = PluginDescriptor.WHERE_PLUGINMENU,
686                          fnc = main,
687                          icon="plugin.png"
688                          ),
689                 ]