Back to index

python3.2  3.2.2
Public Member Functions | Public Attributes | Static Public Attributes | Private Attributes
test.test_smtplib.SimSMTPChannel Class Reference
Inheritance diagram for test.test_smtplib.SimSMTPChannel:
Inheritance graph
[legend]
Collaboration diagram for test.test_smtplib.SimSMTPChannel:
Collaboration graph
[legend]

List of all members.

Public Member Functions

def __init__
def smtp_EHLO
def smtp_VRFY
def smtp_EXPN
def smtp_AUTH
def handle_error
def push
def collect_incoming_data
def found_terminator
def smtp_HELO
def smtp_NOOP
def smtp_QUIT
def smtp_MAIL
def smtp_RCPT
def smtp_RSET
def smtp_DATA
def set_terminator
def get_terminator
def handle_read
def handle_write
def handle_close
def push_with_producer
def readable
def writable
def close_when_done
def initiate_send
def discard_buffers
def __repr__
def add_channel
def del_channel
def create_socket
def set_socket

Public Attributes

 smtp_server
 conn
 addr
 received_lines
 smtp_state
 seen_greeting
 mailfrom
 rcpttos
 received_data
 fqdn
 num_bytes
 peer
 ac_in_buffer
 incoming
 producer_fifo
 terminator
 socket
 family_and_type

Static Public Attributes

int COMMAND = 0
int DATA = 1
int data_size_limit = 33554432
int command_size_limit = 512
int ac_in_buffer_size = 4096
int ac_out_buffer_size = 4096
int use_encoding = 0
string encoding = 'latin1'
 debug = False
 connected = False
 accepting = False
 closing = False
tuple ignore_log_types = frozenset(['warning'])

Private Attributes

 _extrafeatures

Detailed Description

Definition at line 563 of file test_smtplib.py.


Constructor & Destructor Documentation

def test.test_smtplib.SimSMTPChannel.__init__ (   self,
  extra_features,
  args,
  kw 
)

Reimplemented from smtpd.SMTPChannel.

Definition at line 565 of file test_smtplib.py.

00565 
00566     def __init__(self, extra_features, *args, **kw):
00567         self._extrafeatures = ''.join(
00568             [ "250-{0}\r\n".format(x) for x in extra_features ])
00569         super(SimSMTPChannel, self).__init__(*args, **kw)

Here is the caller graph for this function:


Member Function Documentation

def asyncore.dispatcher.__repr__ (   self) [inherited]

Definition at line 264 of file asyncore.py.

00264 
00265     def __repr__(self):
00266         status = [self.__class__.__module__+"."+self.__class__.__name__]
00267         if self.accepting and self.addr:
00268             status.append('listening')
00269         elif self.connected:
00270             status.append('connected')
00271         if self.addr is not None:
00272             try:
00273                 status.append('%s:%d' % self.addr)
00274             except TypeError:
00275                 status.append(repr(self.addr))
00276         return '<%s at %#x>' % (' '.join(status), id(self))

def asyncore.dispatcher.add_channel (   self,
  map = None 
) [inherited]

Definition at line 279 of file asyncore.py.

00279 
00280     def add_channel(self, map=None):
00281         #self.log_info('adding channel %s' % self)
00282         if map is None:
00283             map = self._map
00284         map[self._fileno] = self

Here is the caller graph for this function:

def asynchat.async_chat.close_when_done (   self) [inherited]

Definition at line 224 of file asynchat.py.

00224 
00225     def close_when_done (self):
00226         "automatically close this channel once the outgoing queue is empty"
00227         self.producer_fifo.append(None)

Here is the caller graph for this function:

def smtpd.SMTPChannel.collect_incoming_data (   self,
  data 
) [inherited]

Reimplemented from asynchat.async_chat.

Definition at line 268 of file smtpd.py.

00268 
00269     def collect_incoming_data(self, data):
00270         limit = None
00271         if self.smtp_state == self.COMMAND:
00272             limit = self.command_size_limit
00273         elif self.smtp_state == self.DATA:
00274             limit = self.data_size_limit
00275         if limit and self.num_bytes > limit:
00276             return
00277         elif limit:
00278             self.num_bytes += len(data)
00279         self.received_lines.append(str(data, "utf8"))

def asyncore.dispatcher.create_socket (   self,
  family,
  type 
) [inherited]

Definition at line 294 of file asyncore.py.

00294 
00295     def create_socket(self, family, type):
00296         self.family_and_type = family, type
00297         sock = socket.socket(family, type)
00298         sock.setblocking(0)
00299         self.set_socket(sock)

Here is the caller graph for this function:

def asyncore.dispatcher.del_channel (   self,
  map = None 
) [inherited]

Definition at line 285 of file asyncore.py.

00285 
00286     def del_channel(self, map=None):
00287         fd = self._fileno
00288         if map is None:
00289             map = self._map
00290         if fd in map:
00291             #self.log_info('closing channel %d:%s' % (fd, self))
00292             del map[fd]
00293         self._fileno = None

Here is the caller graph for this function:

def asynchat.async_chat.discard_buffers (   self) [inherited]

Definition at line 270 of file asynchat.py.

00270 
00271     def discard_buffers (self):
00272         # Emergencies only!
00273         self.ac_in_buffer = b''
00274         del self.incoming[:]
00275         self.producer_fifo.clear()

def smtpd.SMTPChannel.found_terminator (   self) [inherited]

Reimplemented from asynchat.async_chat.

Definition at line 281 of file smtpd.py.

00281 
00282     def found_terminator(self):
00283         line = EMPTYSTRING.join(self.received_lines)
00284         print('Data:', repr(line), file=DEBUGSTREAM)
00285         self.received_lines = []
00286         if self.smtp_state == self.COMMAND:
00287             if self.num_bytes > self.command_size_limit:
00288                 self.push('500 Error: line too long')
00289                 self.num_bytes = 0
00290                 return
00291             self.num_bytes = 0
00292             if not line:
00293                 self.push('500 Error: bad syntax')
00294                 return
00295             method = None
00296             i = line.find(' ')
00297             if i < 0:
00298                 command = line.upper()
00299                 arg = None
00300             else:
00301                 command = line[:i].upper()
00302                 arg = line[i+1:].strip()
00303             method = getattr(self, 'smtp_' + command, None)
00304             if not method:
00305                 self.push('502 Error: command "%s" not implemented' % command)
00306                 return
00307             method(arg)
00308             return
00309         else:
00310             if self.smtp_state != self.DATA:
00311                 self.push('451 Internal confusion')
00312                 self.num_bytes = 0
00313                 return
00314             if self.num_bytes > self.data_size_limit:
00315                 self.push('552 Error: Too much mail data')
00316                 self.num_bytes = 0
00317                 return
00318             # Remove extraneous carriage returns and de-transparency according
00319             # to RFC 821, Section 4.5.2.
00320             data = []
00321             for text in line.split('\r\n'):
00322                 if text and text[0] == '.':
00323                     data.append(text[1:])
00324                 else:
00325                     data.append(text)
00326             self.received_data = NEWLINE.join(data)
00327             status = self.smtp_server.process_message(self.peer,
00328                                                       self.mailfrom,
00329                                                       self.rcpttos,
00330                                                       self.received_data)
00331             self.rcpttos = []
00332             self.mailfrom = None
00333             self.smtp_state = self.COMMAND
00334             self.num_bytes = 0
00335             self.set_terminator(b'\r\n')
00336             if not status:
00337                 self.push('250 Ok')
00338             else:
00339                 self.push(status)

Here is the call graph for this function:

def asynchat.async_chat.get_terminator (   self) [inherited]

Definition at line 117 of file asynchat.py.

00117 
00118     def get_terminator (self):
00119         return self.terminator

Here is the caller graph for this function:

def asynchat.async_chat.handle_close (   self) [inherited]

Reimplemented in test.test_ftplib.DummyDTPHandler.

Definition at line 196 of file asynchat.py.

00196 
00197     def handle_close (self):
00198         self.close()

Here is the caller graph for this function:

Definition at line 615 of file test_smtplib.py.

00615 
00616     def handle_error(self):
00617         raise
00618 

Here is the caller graph for this function:

def asynchat.async_chat.handle_read (   self) [inherited]

Reimplemented in test.test_poplib.DummyPOP3_SSLHandler, and test.test_ftplib.DummyDTPHandler.

Definition at line 125 of file asynchat.py.

00125 
00126     def handle_read (self):
00127 
00128         try:
00129             data = self.recv (self.ac_in_buffer_size)
00130         except socket.error as why:
00131             self.handle_error()
00132             return
00133 
00134         if isinstance(data, str) and self.use_encoding:
00135             data = bytes(str, self.encoding)
00136         self.ac_in_buffer = self.ac_in_buffer + data
00137 
00138         # Continue to search for self.terminator in self.ac_in_buffer,
00139         # while calling self.collect_incoming_data.  The while loop
00140         # is necessary because we might read several data+terminator
00141         # combos with a single recv(4096).
00142 
00143         while self.ac_in_buffer:
00144             lb = len(self.ac_in_buffer)
00145             terminator = self.get_terminator()
00146             if not terminator:
00147                 # no terminator, collect it all
00148                 self.collect_incoming_data (self.ac_in_buffer)
00149                 self.ac_in_buffer = b''
00150             elif isinstance(terminator, int):
00151                 # numeric terminator
00152                 n = terminator
00153                 if lb < n:
00154                     self.collect_incoming_data (self.ac_in_buffer)
00155                     self.ac_in_buffer = b''
00156                     self.terminator = self.terminator - lb
00157                 else:
00158                     self.collect_incoming_data (self.ac_in_buffer[:n])
00159                     self.ac_in_buffer = self.ac_in_buffer[n:]
00160                     self.terminator = 0
00161                     self.found_terminator()
00162             else:
00163                 # 3 cases:
00164                 # 1) end of buffer matches terminator exactly:
00165                 #    collect data, transition
00166                 # 2) end of buffer matches some prefix:
00167                 #    collect data to the prefix
00168                 # 3) end of buffer does not match any prefix:
00169                 #    collect data
00170                 terminator_len = len(terminator)
00171                 index = self.ac_in_buffer.find(terminator)
00172                 if index != -1:
00173                     # we found the terminator
00174                     if index > 0:
00175                         # don't bother reporting the empty string (source of subtle bugs)
00176                         self.collect_incoming_data (self.ac_in_buffer[:index])
00177                     self.ac_in_buffer = self.ac_in_buffer[index+terminator_len:]
00178                     # This does the Right Thing if the terminator is changed here.
00179                     self.found_terminator()
00180                 else:
00181                     # check for a prefix of the terminator
00182                     index = find_prefix_at_end (self.ac_in_buffer, terminator)
00183                     if index:
00184                         if index != lb:
00185                             # we found a prefix, collect up to the prefix
00186                             self.collect_incoming_data (self.ac_in_buffer[:-index])
00187                             self.ac_in_buffer = self.ac_in_buffer[-index:]
00188                         break
00189                     else:
00190                         # no prefix, collect it all
00191                         self.collect_incoming_data (self.ac_in_buffer)
00192                         self.ac_in_buffer = b''

Here is the call graph for this function:

def asynchat.async_chat.handle_write (   self) [inherited]

Definition at line 193 of file asynchat.py.

00193 
00194     def handle_write (self):
00195         self.initiate_send()

Here is the call graph for this function:

def asynchat.async_chat.initiate_send (   self) [inherited]

Definition at line 228 of file asynchat.py.

00228 
00229     def initiate_send(self):
00230         while self.producer_fifo and self.connected:
00231             first = self.producer_fifo[0]
00232             # handle empty string/buffer or None entry
00233             if not first:
00234                 del self.producer_fifo[0]
00235                 if first is None:
00236                     ## print("first is None")
00237                     self.handle_close()
00238                     return
00239                 ## print("first is not None")
00240 
00241             # handle classic producer behavior
00242             obs = self.ac_out_buffer_size
00243             try:
00244                 data = buffer(first, 0, obs)
00245             except TypeError:
00246                 data = first.more()
00247                 if data:
00248                     self.producer_fifo.appendleft(data)
00249                 else:
00250                     del self.producer_fifo[0]
00251                 continue
00252 
00253             if isinstance(data, str) and self.use_encoding:
00254                 data = bytes(data, self.encoding)
00255 
00256             # send the data
00257             try:
00258                 num_sent = self.send(data)
00259             except socket.error:
00260                 self.handle_error()
00261                 return
00262 
00263             if num_sent:
00264                 if num_sent < len(data) or obs < len(first):
00265                     self.producer_fifo[0] = first[num_sent:]
00266                 else:
00267                     del self.producer_fifo[0]
00268             # we tried to send some actual data
00269             return

Here is the call graph for this function:

Here is the caller graph for this function:

def smtpd.SMTPChannel.push (   self,
  msg 
) [inherited]

Reimplemented from asynchat.async_chat.

Definition at line 264 of file smtpd.py.

00264 
00265     def push(self, msg):
00266         asynchat.async_chat.push(self, bytes(msg + '\r\n', 'ascii'))

Here is the call graph for this function:

def asynchat.async_chat.push_with_producer (   self,
  producer 
) [inherited]

Definition at line 208 of file asynchat.py.

00208 
00209     def push_with_producer (self, producer):
00210         self.producer_fifo.append(producer)
00211         self.initiate_send()

Here is the call graph for this function:

def asynchat.async_chat.readable (   self) [inherited]

Definition at line 212 of file asynchat.py.

00212 
00213     def readable (self):
00214         "predicate for inclusion in the readable for select()"
00215         # cannot use the old predicate, it violates the claim of the
00216         # set_terminator method.
00217 
00218         # return (len(self.ac_in_buffer) <= self.ac_in_buffer_size)
00219         return 1

def asyncore.dispatcher.set_socket (   self,
  sock,
  map = None 
) [inherited]

Definition at line 300 of file asyncore.py.

00300 
00301     def set_socket(self, sock, map=None):
        self.socket = sock

Here is the call graph for this function:

Here is the caller graph for this function:

def asynchat.async_chat.set_terminator (   self,
  term 
) [inherited]

Definition at line 111 of file asynchat.py.

00111 
00112     def set_terminator (self, term):
00113         "Set the input delimiter.  Can be a fixed string of any length, an integer, or None"
00114         if isinstance(term, str) and self.use_encoding:
00115             term = bytes(term, self.encoding)
00116         self.terminator = term

Here is the caller graph for this function:

def test.test_smtplib.SimSMTPChannel.smtp_AUTH (   self,
  arg 
)

Definition at line 599 of file test_smtplib.py.

00599 
00600     def smtp_AUTH(self, arg):
00601         if arg.strip().lower()=='cram-md5':
00602             self.push('334 {}'.format(sim_cram_md5_challenge))
00603             return
00604         mech, auth = arg.split()
00605         mech = mech.lower()
00606         if mech not in sim_auth_credentials:
00607             self.push('504 auth type unimplemented')
00608             return
00609         if mech == 'plain' and auth==sim_auth_credentials['plain']:
00610             self.push('235 plain auth ok')
00611         elif mech=='login' and auth==sim_auth_credentials['login']:
00612             self.push('334 Password:')
00613         else:
00614             self.push('550 No access for you!')

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_DATA (   self,
  arg 
) [inherited]

Definition at line 413 of file smtpd.py.

00413 
00414     def smtp_DATA(self, arg):
00415         if not self.rcpttos:
00416             self.push('503 Error: need RCPT command')
00417             return
00418         if arg:
00419             self.push('501 Syntax: DATA')
00420             return
00421         self.smtp_state = self.DATA
00422         self.set_terminator(b'\r\n.\r\n')
00423         self.push('354 End data with <CR><LF>.<CR><LF>')
00424 
00425 


Here is the call graph for this function:

def test.test_smtplib.SimSMTPChannel.smtp_EHLO (   self,
  arg 
)

Definition at line 570 of file test_smtplib.py.

00570 
00571     def smtp_EHLO(self, arg):
00572         resp = ('250-testhost\r\n'
00573                 '250-EXPN\r\n'
00574                 '250-SIZE 20000000\r\n'
00575                 '250-STARTTLS\r\n'
00576                 '250-DELIVERBY\r\n')
00577         resp = resp + self._extrafeatures + '250 HELP'
00578         self.push(resp)

Here is the call graph for this function:

def test.test_smtplib.SimSMTPChannel.smtp_EXPN (   self,
  arg 
)

Definition at line 586 of file test_smtplib.py.

00586 
00587     def smtp_EXPN(self, arg):
00588         list_name = arg.lower()
00589         if list_name in sim_lists:
00590             user_list = sim_lists[list_name]
00591             for n, user_email in enumerate(user_list):
00592                 quoted_addr = smtplib.quoteaddr(user_email)
00593                 if n < len(user_list) - 1:
00594                     self.push('250-%s %s' % (sim_users[user_email], quoted_addr))
00595                 else:
00596                     self.push('250 %s %s' % (sim_users[user_email], quoted_addr))
00597         else:
00598             self.push('550 No access for you!')

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_HELO (   self,
  arg 
) [inherited]

Definition at line 341 of file smtpd.py.

00341 
00342     def smtp_HELO(self, arg):
00343         if not arg:
00344             self.push('501 Syntax: HELO hostname')
00345             return
00346         if self.seen_greeting:
00347             self.push('503 Duplicate HELO/EHLO')
00348         else:
00349             self.seen_greeting = arg
00350             self.push('250 %s' % self.fqdn)

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_MAIL (   self,
  arg 
) [inherited]

Definition at line 376 of file smtpd.py.

00376 
00377     def smtp_MAIL(self, arg):
00378         print('===> MAIL', arg, file=DEBUGSTREAM)
00379         address = self.__getaddr('FROM:', arg) if arg else None
00380         if not address:
00381             self.push('501 Syntax: MAIL FROM:<address>')
00382             return
00383         if self.mailfrom:
00384             self.push('503 Error: nested MAIL command')
00385             return
00386         self.mailfrom = address
00387         print('sender:', self.mailfrom, file=DEBUGSTREAM)
00388         self.push('250 Ok')

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_NOOP (   self,
  arg 
) [inherited]

Definition at line 351 of file smtpd.py.

00351 
00352     def smtp_NOOP(self, arg):
00353         if arg:
00354             self.push('501 Syntax: NOOP')
00355         else:
00356             self.push('250 Ok')

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_QUIT (   self,
  arg 
) [inherited]

Definition at line 357 of file smtpd.py.

00357 
00358     def smtp_QUIT(self, arg):
00359         # args is ignored
00360         self.push('221 Bye')
00361         self.close_when_done()

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_RCPT (   self,
  arg 
) [inherited]

Definition at line 389 of file smtpd.py.

00389 
00390     def smtp_RCPT(self, arg):
00391         print('===> RCPT', arg, file=DEBUGSTREAM)
00392         if not self.mailfrom:
00393             self.push('503 Error: need MAIL command')
00394             return
00395         address = self.__getaddr('TO:', arg) if arg else None
00396         if not address:
00397             self.push('501 Syntax: RCPT TO: <address>')
00398             return
00399         self.rcpttos.append(address)
00400         print('recips:', self.rcpttos, file=DEBUGSTREAM)
00401         self.push('250 Ok')

Here is the call graph for this function:

def smtpd.SMTPChannel.smtp_RSET (   self,
  arg 
) [inherited]

Definition at line 402 of file smtpd.py.

00402 
00403     def smtp_RSET(self, arg):
00404         if arg:
00405             self.push('501 Syntax: RSET')
00406             return
00407         # Resets the sender, recipients, and data, but not the greeting
00408         self.mailfrom = None
00409         self.rcpttos = []
00410         self.received_data = ''
00411         self.smtp_state = self.COMMAND
00412         self.push('250 Ok')

Here is the call graph for this function:

def test.test_smtplib.SimSMTPChannel.smtp_VRFY (   self,
  arg 
)

Definition at line 579 of file test_smtplib.py.

00579 
00580     def smtp_VRFY(self, arg):
00581         # For max compatibility smtplib should be sending the raw address.
00582         if arg in sim_users:
00583             self.push('250 %s %s' % (sim_users[arg], smtplib.quoteaddr(arg)))
00584         else:
00585             self.push('550 No such user: %s' % arg)

Here is the call graph for this function:

def asynchat.async_chat.writable (   self) [inherited]

Definition at line 220 of file asynchat.py.

00220 
00221     def writable (self):
00222         "predicate for inclusion in the writable for select()"
00223         return self.producer_fifo or (not self.connected)


Member Data Documentation

Definition at line 566 of file test_smtplib.py.

Definition at line 82 of file asynchat.py.

int asynchat.async_chat.ac_in_buffer_size = 4096 [static, inherited]

Definition at line 71 of file asynchat.py.

int asynchat.async_chat.ac_out_buffer_size = 4096 [static, inherited]

Definition at line 72 of file asynchat.py.

asyncore.dispatcher.accepting = False [static, inherited]

Definition at line 227 of file asyncore.py.

Reimplemented from asyncore.dispatcher.

Definition at line 119 of file smtpd.py.

asyncore.dispatcher.closing = False [static, inherited]

Definition at line 228 of file asyncore.py.

int smtpd.SMTPChannel.COMMAND = 0 [static, inherited]

Definition at line 109 of file smtpd.py.

int smtpd.SMTPChannel.command_size_limit = 512 [static, inherited]

Definition at line 113 of file smtpd.py.

Definition at line 118 of file smtpd.py.

asyncore.dispatcher.connected = False [static, inherited]

Reimplemented in asyncore.file_dispatcher.

Definition at line 226 of file asyncore.py.

int smtpd.SMTPChannel.DATA = 1 [static, inherited]

Definition at line 110 of file smtpd.py.

int smtpd.SMTPChannel.data_size_limit = 33554432 [static, inherited]

Definition at line 112 of file smtpd.py.

asyncore.dispatcher.debug = False [static, inherited]

Definition at line 225 of file asyncore.py.

string asynchat.async_chat.encoding = 'latin1' [static, inherited]

Definition at line 78 of file asynchat.py.

Definition at line 295 of file asyncore.py.

Definition at line 126 of file smtpd.py.

tuple asyncore.dispatcher.ignore_log_types = frozenset(['warning']) [static, inherited]

Definition at line 230 of file asyncore.py.

Definition at line 90 of file asynchat.py.

Definition at line 123 of file smtpd.py.

Definition at line 127 of file smtpd.py.

Definition at line 129 of file smtpd.py.

Definition at line 94 of file asynchat.py.

Definition at line 124 of file smtpd.py.

Definition at line 125 of file smtpd.py.

Definition at line 120 of file smtpd.py.

Definition at line 122 of file smtpd.py.

Definition at line 117 of file smtpd.py.

Definition at line 121 of file smtpd.py.

Definition at line 115 of file asynchat.py.

int asynchat.async_chat.use_encoding = 0 [static, inherited]

Definition at line 77 of file asynchat.py.


The documentation for this class was generated from the following file: