Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Ke-
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ke-/54b5ba95b9490070e7a6 to your computer and use it in GitHub Desktop.
Save Ke-/54b5ba95b9490070e7a6 to your computer and use it in GitHub Desktop.
pop type for Lasso 9 — converted from a L8.x type floating around.
<?lasso
define pop => type {
data
public pop_net = null,
public pop_mode = '',
public pop_timeout = 15,
public pop_token = '',
public pop_index = 0,
public pop_err = array,
public pop_res = array,
public pop_log = false,
public pop_debug = false,
public pop_get = 'retr',
public pop_ids = map,
public pop_capa = null,
public pop_server = ''
public oncreate => {}
public oncreate(
server::string,
-host::string = '',
-port::integer = 110,
-username::string ='',
-password::string = '',
-timeout::integer = 15,
-get::string = 'uidl',
-apop = false,
-log = false,
-debug = false,
-ssl = false
) => {
local(
net = net_tcpssl,
server = #server || #host ,
capa
)
.pop_net = #net
.pop_get = #get
.pop_log = #log
.pop_debug = #debug
.pop_timeout = #timeout
.pop_server = #server
debug('server' = #server)
debug('port' = #port)
if(#net->connect(#server,#port,#timeout)) => {
debug('b' = 'connected')
debug('c' = #net->type)
debug('->listmethods' =#net->listmethods)
debug('->beginTLS' =#net->beginTLS(1))
#net->writebytes('USER '+#username +'\r\n'->asbytes)
debug('readsomebytes' = #net->readsomebytes(1000,1))
return self
// #net->beginTLS
.pop_capa = map
/*
#capa = .capabilities
if(#ssl) => {
if(#capa >> 'STLS') => {
.stls
else
.pop_err('Could not open SSL communications',-cmd='STLS')
}
}
*/
if(#username) => {
debug('authorize')
.authorize(
-username = #username,
-password = #password,
-apop = #apop
)
}
}
}
public pop_cmd(
command::string,
-timeout::integer = .pop_timeout,
-multi = false,
-until = ''
) => {
! #command->endswith('\r\n')
? #command->append('\r\n')
debug->open('pop_cmd')
handle => {debug->close}
debug(params)
local(
net = .pop_net,
result = '',
tmp = true,
write,
i = 0
)
debug('command'= #command)
debug('command->endswith' = #command->endswith('\r\n'))
if(#net->isanyof(::net_tcp,::net_tcpssl)) => {
#write = #net->writeBytes(#command->asbytes,1)
debug('write' = #write)
if(#until) => {
while(#result !>> #until && #i++ < 32768) => {
#result->append(#net->readSomeBytes(1,1))
}
.pop_log(#result->split('\r\n')->get(1)->asstring,-cmd=#command)
else
debug('#net->readSomeBytes(1)' = #net->readSomeBytes(1))
while(#result !>> '\r\n' && #i++ < 32768) => {
#result->append(
#net->readSomeBytes(1)
)
}
debug(#i)
#i = 0
#multi ? while(#result !>> '\r\n.\r\n' && #i++ < 1000 && #tmp) => {
#result->append(
#tmp := #net->readSomeBytes(32768)
)
.pop_log('... reading (' + #tmp->size + ' bytes)',-cmd=#command)
}
debug('result' = #result)
}
else
.pop_err('The remote server timed out on read.', -cmd=#command)
}
return #result
}
public user(username::string='') => {
if(#username) => {
return .pop_cmd('USER '+#username)
else
return .pop_err('No username specified.',-cmd='USER')
}
}
public pass(password::string='') => {
if(#password) => {
return .pop_cmd('PASS '+#password)
else
return .pop_err('No password specified.',-cmd='PASS')
}
}
public apop(username::string,password::string) => {
if(.pop_token >> '<') => {
return .pop_cmd('APOP ' + #username + ' ' + encrypt_md5(.pop_token+#password))
else
return .pop_err('No password specified.',-cmd='PASS')
}
}
public quit => {
.pop_mode = 'done'
return .pop_cmd('QUIT')->trim &;
}
public rset => {
return .pop_cmd('RSET')->trim &;
}
public stat => {
return.pop_cmd('STAT')->trim &;
}
public list(msg::integer) => {
if(#msg) => {
return .pop_cmd('LIST ' + #msg)->trim &;
else
return .pop_cmd('LIST', -multi=true)->trim &;
}
}
public uidl(msg::integer) => {
if(#msg) => {
return .pop_cmd('UIDL ' + #msg)->trim &;
else
return .pop_cmd('UIDL', -multi=true)->trim &;
}
}
public retr(msg::integer) => {
return .pop_cmd('RETR ' + #msg, -multi=true)->trim &;
}
public top(msg::integer,size::integer=0) => {
return .pop_cmd('TOP ' + #msg + ' ' + #size, -multi=true)->trim &;
}
public dele(msg::integer) => {
return .pop_cmd('DELE ' + #msg)->trim &;
}
public noop => {
return .pop_cmd('NOOP')->trim &;
}
public capa() => {
return .pop_cmd('CAPA', -multi=true)->trim &;
}
public stls() => {
return .pop_cmd('STLS', -until='\r\n')->trim &;
}
public size => {
protect => {
return string_findregexp(.pop_cmd('STAT'),-find='[0-9]+')->first->asinteger
}
return 0
}
public close => {
.pop_ids = map
.pop_index = 0
.quit
}
public cancel => {
.rset
.close
}
public results => .pop_res
public errors => .pop_err
public lasterror => .pop_err->last
public data => .pop_token
public pop_err(
msg::string,
-code::integer=0,
-cmd::string=''
) => {
.pop_res->insert(#cmd=#msg)
fail(#code,#msg)
}
public pop_log(
msg::string,
-code::string='',
-cmd::string=''
) => {
.pop_res->insert(#cmd=#msg)
error_seterrormessage(error_noerror)
error_seterrorcode(error_noerror(-errorcode))
}
public pop_last => {
protect => {
return .pop_res->last->second->asstring
}
return ''
}
/* Gmail Specific */
public authorize(
-username::string,
-password::string,
-apop = false
) => {
local(
methods,
done
)
if(.pop_capa >> 'sasl') => {
#methods = .pop_capa->find('sasl')
else
#methods = array('LOGIN','PLAIN')
}
if(!#done && #methods >> 'DIGEST-MD5') => {
.auth(-username=#username, -password=#password, -method='DIGEST-MD5')
#done = .pop_res->last->second >> '+ '
}
if(!#done && #methods >> 'CRAM-MD5') => {
.auth(-username=#username, -password=#password, -method='CRAM-MD5')
#done = .pop_res->last->second >> '+OK'
}
if(!#done && #apop && .pop_token >> '<') => {
.apop(-username=#username, -password=#password)
#done = .pop_res->last->second >> '+OK'
}
if(!#done) => {
.capa
.user(#username)
.pass(#password)
#done = .pop_res->last->second >> '+OK'
}
if(!#done) => {
.pop_err('Could not authenticate user.',-cmd='PASS')
else
.pop_mode = 'ready'
}
.pop_ids = map
.pop_index = 0
}
public auth(
-username::string,
-password::string,
-method::string
) => {
local(
result,digest
)
match(#method) => {
case('CRAM-MD5')
#result = .pop_cmd('AUTH CRAM-MD5')
if(#result->beginswith('+ ')) => {
return .pop_cmd(
encode_base64(#username+' '+encrypt_crammd5(#password,#result))
)
else
.pop_err('Invalid response for ' + #method + ' method.',-cmd='AUTH')
}
case('DIGEST-MD5')
#result = .pop_cmd('AUTH DIGEST-MD5')
if(#result->beginswith('+ ')) => {
#result->remove(3)
#digest = email_digestchallenge(decode_base64(#result))
#digest->insert('username' = #username)
#digest->insert('password' = #password)
#digest->insert('digest-uri' = 'pop/' + self->'pop_server')
#digest->insert('cnonce' = (encrypt_md5: lasso_uniqueid))
#digest->insert('nc' = '00000001')
return .pop_cmd(
encode_base64(email_digestresponse(#digest))
)
else
.pop_err('Invalid response for ' + #method + ' method.',-cmd='AUTH')
}
case
.pop_err('Method ' + #method + ' not found.',-cmd='AUTH')
}
#digest = encrypt_md5(.pop_token + #password)
return .pop_cmd('APOP ' + #username + ' ' + #digest)
}
public get(msg::string) => {
local(
msg = .pop_ids->find(#msg)
)
fail_if(!#msg, -9956, '[pop->' + method_name + '] invalid msg index')
return .get(#msg)
}
public get(msg::integer) => {
! #msg
? #msg = .pop_index
if(#msg) => {
match(.pop_get) => {
case('retr')
return .retrieve(#msg)
case('dele')
return .delete(#msg)
case('head')
return .headers(#msg)
case('top')
return .retrieve(#msg,string_replaceregexp(.pop_get, -find='.*(\\d+).*',-replace='\\1')->asinteger)
case
return .uniqueid(#msg)
}
}
return ''
fail(-9956, '[pop->' + method_name + '] invalid msg index.')
}
public retrieve(msg::integer,size::integer=0) => {
local(result)
if(#msg) => {
if(#size) => {
#result = .top(#msg,#size)
else
#result = .retr(#msg)
}
fail_if(
#result->beginswith('-ERR'), -9956,
'The tag [Email_POP->' + tag_name + '] did not find a message at provided position (' + #msg ').'
)
#result = #result->substring(1,#result->find('\r\n')+2)
#result->trim
#result->removetrailing('\r\n.')
return #result
else
return ''
}
}
public headers(msg::integer) => {
local(result)
if(#msg) => {
#result = .top(#msg,0)
fail_if(
#result->beginswith('-ERR'), -9956,
'The tag [Email_POP->' + tag_name + '] did not find a message at provided position (' + #msg ').'
)
#result = #result->substring(1,#result->find('\r\n')+2)
#result->trim
#result->removetrailing('\r\n.')
return #result
else
return ''
}
}
public delete(msg::integer) => {
local(result)
if(#msg) => {
#result = .dele(#msg)
fail_if(
#result->beginswith('-ERR'), -9956,
'The tag [Email_POP->' + tag_name + '] did not find a message at provided position (' + #msg ').'
)
}
}
public uniqueid(msg::integer) => {
local(result)
if(#msg) => {
#result = .uidl(#msg)
fail_if(
#result->beginswith('-ERR'), -9956,
'The tag [Email_POP->' + tag_name + '] did not find a message at provided position (' + #msg ').'
)
#result = #result->split(' ')
if(#result->size > 2) => {
#result = #result->get(3)->asinteger
if(#result) => {
.pop_ids->insert(
#result = #msg
)
return #result
}
}
else
return 0
}
}
public capabilities => {
if(.pop_capa->isa(::null)) => {
debug('get capabilities')
local(
capa = map,
result = .capa
)
#result->replace('\r\n','\n')
#result->replace('\r','\n')
with tmp in #result->split('\n') do {
if(#tmp && !#tmp->beginswith('+') && !#tmp->beginswith('.')) => {
if(#tmp >> ' ') => {
#tmp = #tmp->split(' ')
#capa->insert(
#tmp->first = #tmp->remove(1) &
)
else
#capa->insert(
#tmp = ''
)
}
}
}
debug('#capa'=#capa )
return .pop_capa := #capa
}
return .pop_capa
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment