]>
code.delx.au - offlineimap/blob - offlineimap/imaplibutil.py
2 # Copyright (C) 2002-2007 John Goerzen
3 # <jgoerzen@complete.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 import re
, string
, types
, binascii
, socket
, time
, random
, subprocess
, sys
, os
20 from offlineimap
.ui
import UIBase
22 class IMAP4_Tunnel(imaplib
.IMAP4
):
23 """IMAP4 client class over a tunnel
25 Instantiate with: IMAP4_Tunnel(tunnelcmd)
27 tunnelcmd -- shell command to generate the tunnel.
28 The result will be in PREAUTH stage."""
30 def __init__(self
, tunnelcmd
):
31 imaplib
.IMAP4
.__init__(self
, tunnelcmd
)
33 def open(self
, host
, port
):
34 """The tunnelcmd comes in on host!"""
35 self
.process
= subprocess
.Popen(host
, shell
=True, close_fds
=True,
36 stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
)
37 (self
.outfd
, self
.infd
) = (self
.process
.stdin
, self
.process
.stdout
)
41 while len(retval
) < size
:
42 retval
+= self
.infd
.read(size
- len(retval
))
46 return self
.infd
.readline()
49 self
.outfd
.write(data
)
56 # FIXME: need to use this in SSL instances
58 def __init__(self
, sslsock
):
59 self
.sslsock
= sslsock
63 return self
.sslsock
.write(s
)
66 return self
.sslsock
.read(n
)
70 # Return the stuff in readbuf, even if less than n.
71 # It might contain the rest of the line, and if we try to
72 # read more, might block waiting for data that is not
74 bytesfrombuf
= min(n
, len(self
.readbuf
))
75 retval
= self
.readbuf
[:bytesfrombuf
]
76 self
.readbuf
= self
.readbuf
[bytesfrombuf
:]
78 retval
= self
._read
(n
)
80 self
.readbuf
= retval
[n
:]
87 linebuf
= self
.read(1024)
88 nlindex
= linebuf
.find("\n")
90 retval
+= linebuf
[:nlindex
+ 1]
91 self
.readbuf
= linebuf
[nlindex
+ 1:] + self
.readbuf
96 # FIXME: need to override this in IMAP instances
98 def new_mesg(self
, s
, secs
=None):
101 tm
= time
.strftime('%M:%S', time
.localtime(secs
))
102 UIBase
.getglobalui().debug('imap', ' %s.%02d %s' % (tm
, (secs
*100)%100, s
))
105 def new_open(self
, host
= '', port
= imaplib
.IMAP4_PORT
):
106 """Setup connection to remote server on "host:port"
107 (default: localhost:standard IMAP4 port).
108 This connection will be used by the routines:
109 read, readline, send, shutdown.
113 res
= socket
.getaddrinfo(host
, port
, socket
.AF_UNSPEC
,
115 self
.sock
= socket
.socket(af
, socktype
, proto
)
117 # Try each address returned by getaddrinfo in turn until we
118 # manage to connect to one.
119 # Try all the addresses in turn until we connect()
122 af
, socktype
, proto
, canonname
, sa
= remote
123 self
.sock
= socket
.socket(af
, socktype
, proto
)
124 last_error
= self
.sock
.connect_ex(sa
)
131 raise socket
.error(last_error
)
132 self
.file = self
.sock
.makefile('rb')
134 def new_open_ssl(self
, host
= '', port
= IMAP4_SSL_PORT
):
135 """Setup connection to remote server on "host:port".
136 (default: localhost:standard IMAP4 SSL port).
137 This connection will be used by the routines:
138 read, readline, send, shutdown.
142 #This connects to the first ip found ipv4/ipv6
143 #Added by Adriaan Peeters <apeeters@lashout.net> based on a socket
144 #example from the python documentation:
145 #http://www.python.org/doc/lib/socket-example.html
146 res
= socket
.getaddrinfo(host
, port
, socket
.AF_UNSPEC
,
148 # Try all the addresses in turn until we connect()
151 af
, socktype
, proto
, canonname
, sa
= remote
152 self
.sock
= socket
.socket(af
, socktype
, proto
)
153 last_error
= self
.sock
.connect_ex(sa
)
160 raise socket
.error(last_error
)
161 if sys
.version_info
[0] <= 2 and sys
.version_info
[1] <= 2:
162 self
.sslobj
= socket
.ssl(self
.sock
, self
.keyfile
, self
.certfile
)
164 self
.sslobj
= socket
.ssl(self
.sock
._sock
, self
.keyfile
, self
.certfile
)
165 self
.sslobj
= sslwrapper(self
.sslobj
)
167 mustquote
= re
.compile(r
"[^\w!#$%&'+,.:;<=>?^`|~-]")
169 def Internaldate2epoch(resp
):
170 """Convert IMAP4 INTERNALDATE to UT.
172 Returns seconds since the epoch.
175 mo
= InternalDate
.match(resp
)
179 mon
= Mon2num
[mo
.group('mon')]
180 zonen
= mo
.group('zonen')
182 day
= int(mo
.group('day'))
183 year
= int(mo
.group('year'))
184 hour
= int(mo
.group('hour'))
185 min = int(mo
.group('min'))
186 sec
= int(mo
.group('sec'))
187 zoneh
= int(mo
.group('zoneh'))
188 zonem
= int(mo
.group('zonem'))
190 # INTERNALDATE timezone must be subtracted to get UT
192 zone
= (zoneh
*60 + zonem
)*60
196 tt
= (year
, mon
, day
, hour
, min, sec
, -1, -1, -1)
198 return time
.mktime(tt
)