diff options
author | schmonz <schmonz@pkgsrc.org> | 2008-10-23 04:40:55 +0000 |
---|---|---|
committer | schmonz <schmonz@pkgsrc.org> | 2008-10-23 04:40:55 +0000 |
commit | df59a1c24c14443e4a752dadec42eafa2925a404 (patch) | |
tree | 14cfc2809703329db96993e8a48c864dba946156 /mail/freepops | |
parent | 949c8f53db8c70d72314c12004bc0f4e1225d29a (diff) | |
download | pkgsrc-df59a1c24c14443e4a752dadec42eafa2925a404.tar.gz |
Update to 0.2.7. From the changelog:
* A huge set of patches for modules and plugins, many thanks to all
the contributors (hope to list them all): cdmack, Viruzzo,
Lance, maxadamo, nvhs, russell822, Andre Martin, Daniel Black,
Picov, RISKO Gergely, blackmoon and Spil
* A new zenity-based (GNOME eye-candy) updater interface by maxadamo
* Internationalization support (and Italian localization) for the
regular fltk updater by blackmoon
* Updated versions of the cURL and gnutls libraries for Windows
* The luasocket library is now part of freepops and can be used to
write modules
We still avoid installing any of the self-updaters. Might be nice
to add in a future PKGREVISION.
Diffstat (limited to 'mail/freepops')
-rw-r--r-- | mail/freepops/Makefile | 8 | ||||
-rw-r--r-- | mail/freepops/PLIST | 10 | ||||
-rw-r--r-- | mail/freepops/distinfo | 24 | ||||
-rw-r--r-- | mail/freepops/files/hotmail.lua | 2002 | ||||
-rw-r--r-- | mail/freepops/patches/patch-aa | 10 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ab | 18 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ac | 14 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ad | 20 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ae | 4 | ||||
-rw-r--r-- | mail/freepops/patches/patch-af | 6 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ag | 6 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ah | 1043 | ||||
-rw-r--r-- | mail/freepops/patches/patch-ai | 526 |
13 files changed, 1632 insertions, 2059 deletions
diff --git a/mail/freepops/Makefile b/mail/freepops/Makefile index b3bb5922b78..9090dd835c8 100644 --- a/mail/freepops/Makefile +++ b/mail/freepops/Makefile @@ -1,8 +1,7 @@ -# $NetBSD: Makefile,v 1.9 2008/06/12 02:14:34 joerg Exp $ +# $NetBSD: Makefile,v 1.10 2008/10/23 04:40:55 schmonz Exp $ # -DISTNAME= freepops-0.2.5 -PKGREVISION= 2 +DISTNAME= freepops-0.2.7 CATEGORIES= mail MASTER_SITES= ${MASTER_SITE_SOURCEFORGE:=freepops/} @@ -53,9 +52,6 @@ FILES_SUBST+= FREEPOPSD_GROUP=${FREEPOPSD_GROUP:Q} PKG_GROUPS_VARS+= FREEPOPSD_GROUP PKG_USERS_VARS+= FREEPOPSD_USER -post-extract: - cp ${FILESDIR}/hotmail.lua ${WRKSRC}/src/lua/hotmail.lua - .include "../../security/openssl/buildlink3.mk" .include "../../textproc/expat/buildlink3.mk" .include "../../www/curl/buildlink3.mk" diff --git a/mail/freepops/PLIST b/mail/freepops/PLIST index f5ad7bd6945..6fc0b6dd278 100644 --- a/mail/freepops/PLIST +++ b/mail/freepops/PLIST @@ -1,17 +1,18 @@ -@comment $NetBSD: PLIST,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ +@comment $NetBSD: PLIST,v 1.2 2008/10/23 04:40:55 schmonz Exp $ bin/freepopsd man/man1/freepopsd.1 share/doc/freepops/MANUAL.txt share/examples/freepops/config.lua share/examples/rc.d/freepopsd +share/freepops/lua/abv.lua share/freepops/lua/aggregator.lua share/freepops/lua/aol.lua share/freepops/lua/browser/browser.lua share/freepops/lua/browser/cookie.lua share/freepops/lua/common.lua share/freepops/lua/config.lua -share/freepops/lua/criticalpath.lua share/freepops/lua/davmail.lua +share/freepops/lua/excite.lua share/freepops/lua/fastmail.lua share/freepops/lua/flatnuke.lua share/freepops/lua/foo.lua @@ -27,13 +28,18 @@ share/freepops/lua/lycos.lua share/freepops/lua/mail2world.lua share/freepops/lua/mailcom.lua share/freepops/lua/mimer.lua +share/freepops/lua/monitor.lua share/freepops/lua/netscape.lua +share/freepops/lua/orange.lua share/freepops/lua/plugins2xml.lua share/freepops/lua/popforward.lua +share/freepops/lua/psock.lua share/freepops/lua/serial.lua share/freepops/lua/skeleton.lua share/freepops/lua/soap/http.lua share/freepops/lua/soap/soap.lua +share/freepops/lua/socket.lua +share/freepops/lua/softhome.lua share/freepops/lua/squirrelmail.lua share/freepops/lua/supereva.lua share/freepops/lua/support.lua diff --git a/mail/freepops/distinfo b/mail/freepops/distinfo index 07fb885c225..370508ec255 100644 --- a/mail/freepops/distinfo +++ b/mail/freepops/distinfo @@ -1,12 +1,14 @@ -$NetBSD: distinfo,v 1.3 2007/06/28 16:36:44 schmonz Exp $ +$NetBSD: distinfo,v 1.4 2008/10/23 04:40:55 schmonz Exp $ -SHA1 (freepops-0.2.5.tar.gz) = 008d8e1504dc0f58119358f73cf2820ba6d0a044 -RMD160 (freepops-0.2.5.tar.gz) = 1f3c64c82c3ff7a75dd11a5ad8bd6366d1fccd4d -Size (freepops-0.2.5.tar.gz) = 1896775 bytes -SHA1 (patch-aa) = ec061d8423a8766dd1b1d97609a0d9cda28d0618 -SHA1 (patch-ab) = e26c06b7d220cf8b7b86f53958f5be784e70c59b -SHA1 (patch-ac) = cb40726dac6fa0e5dc993c8745df41b15044b90f -SHA1 (patch-ad) = 8dbf4703ad2ec63b3ddce0f83e7b627deb92ee7f -SHA1 (patch-ae) = 62468b14d55fdfa7b800daab232c7d22724ec4dc -SHA1 (patch-af) = 172e21a41221e99d4e1a01846e2f6e5c057fefa4 -SHA1 (patch-ag) = 4719cad79d1b391bf3e788ad0930f153f53570ed +SHA1 (freepops-0.2.7.tar.gz) = ea6e5836d26388080b3624aa07808abc1917879c +RMD160 (freepops-0.2.7.tar.gz) = 8504d1e2be40a44955c8ad0907f98dcea9d1a6ac +Size (freepops-0.2.7.tar.gz) = 1955240 bytes +SHA1 (patch-aa) = e5fd37ed3009fda5cc033fe9768b97f3023d6200 +SHA1 (patch-ab) = 59faa97775853f795f024585e194a060a3f3ee94 +SHA1 (patch-ac) = ca0c136b6cee3c164c9382227bcbd534e382927b +SHA1 (patch-ad) = 90a2313b2e9a3a2321778df515c076e603955502 +SHA1 (patch-ae) = 389693569e978395f2d1e286003ad7d20ce59a14 +SHA1 (patch-af) = 68bacbbb3dca7b7e676caee54fc7610c6b280f10 +SHA1 (patch-ag) = 6be408e7c065d9cf32f727e1cbd016b7ce60e202 +SHA1 (patch-ah) = e54224faa6e803e0dd858211416fb5be151d7474 +SHA1 (patch-ai) = 36285e7b1fe68511ad65302a94f2c71e8f348323 diff --git a/mail/freepops/files/hotmail.lua b/mail/freepops/files/hotmail.lua deleted file mode 100644 index 76ca83cf5c0..00000000000 --- a/mail/freepops/files/hotmail.lua +++ /dev/null @@ -1,2002 +0,0 @@ --- ************************************************************************** -- --- FreePOPs @hotmail.com webmail interface --- --- Released under the GNU/GPL license --- Written by Russell Schwager <russell822@yahoo.com> --- Patched by cdmackie (2007-09-11). --- Fixed: lite login, live delete, corrupt messages, stuck at 1st message, classic delete more than 1 message --- ************************************************************************** -- - --- Globals --- -PLUGIN_VERSION = "0.1.84" -PLUGIN_NAME = "hotmail.com" -PLUGIN_REQUIRE_VERSION = "0.2.0" -PLUGIN_LICENSE = "GNU/GPL" -PLUGIN_URL = "http://www.freepops.org/download.php?module=hotmail.lua" -PLUGIN_HOMEPAGE = "http://www.freepops.org/" -PLUGIN_AUTHORS_NAMES = {"Russell Schwager", "D. Milne", "Peter Collingbourne" } -PLUGIN_AUTHORS_CONTACTS = {"russell822 (at) yahoo (.) com", "drmilne (at) safe-mail (.) net", "pcc03 (at) doc (.) ic (.) ac (.) uk>"} -PLUGIN_DOMAINS = { "@hotmail.com","@msn.com","@webtv.com", - "@charter.com", "@compaq.net","@passport.com", - "@hotmail.de", "@hotmail.it", "@hotmail.co.uk", - "@hotmail.co.jp", "@hotmail.fr", "@messengeruser.com", - "@hotmail.com.ar", "@hotmail.co.th", "@hotmail.com.tr" - } -PLUGIN_PARAMETERS = { - {name="folder", description={ - it=[[La cartella che vuoi ispezionare. Quella di default è Inbox.]], - en=[[The folder you want to interact with. Default is Inbox.]]} - }, - {name = "emptyjunk", description = { - en = [[ -Parameter is used to force the plugin to empty the junk folder when it is done -pulling messages. Set the value to 1.]] - } - }, - {name = "emptytrash", description = { - it = [[ Viene usato per forzare il plugin a svuotare il cestino quando ha finito di scaricare i messaggi. Se il valore è 1 questo comportamento viene attivato.]], - en = [[ -Parameter is used to force the plugin to empty the trash when it is done -pulling messages. Set the value to 1.]] - } - }, - {name = "markunread", description = { - it = [[ Viene usato per far sì che il plugin segni come non letti i messaggi che scarica. Se il valore è 1 questo comportamento viene attivato.]], - en = [[ Parameter is used to have the plugin mark all messages that it -pulls as unread. If the value is 1, the behavior is turned on.]] - } - }, - {name = "maxmsgs", description = { - en = [[ -Parameter is used to force the plugin to only download a maximum number of messages. ]] - } - }, - {name = "domain", description = { - en = [[ -Parameter is used to override the domain in the email address. This is used so that users don't -need to add a mapping to config.lua for a hosted hotmail account. ]] - } - }, -} -PLUGIN_DESCRIPTIONS = { - it=[[ -Questo plugin vi permette di scaricare la posta da mailbox con dominio della famiglia di @hotmail.com. -Per usare questo plugin dovrete usare il vostro indirizzo email completo come -nome utente e la vostra vera password come password.]], - en=[[ -This plugin lets you download mail from @hotmail.com and similar mailboxes. -To use this plugin you have to use your full email address as the username -and your real password as the password. For support, please post a question to -the forum instead of emailing the author(s).]] -} - --- Domains supported: hotmail.com, msn.com, webtv.com, charter.com, compaq.net, --- passport.com - --- ************************************************************************** -- --- Global Strings --- ************************************************************************** -- - -local globals = { - -- Max password length in the login page - -- - nMaxPasswordLen = 16, - - -- Server URL - -- - strLoginUrl = "http://mail.live.com/", - - strDefaultLoginPostUrl = "https://login.live.com/ppsecure/post.srf", - - -- Login strings - -- TODO: Define the HTTPS version - -- - strLoginPostData = "login=%s&domain=%s&passwd=%s&sec=&mspp_shared=&PwdPad=%s&PPSX=Pas&LoginOptions=3", - strLoginPaddingFull = "xxxxxxxxxxxxxxxx", - strLoginFailed = "Login Failed - Invalid User name and/or password", - - -- Expressions to pull out of returned HTML from Hotmail corresponding to a problem - -- - strRetLoginBadLogin = "(memberservices)", - strRetLoginSessionExpired = "(Sign in)", - strRetLoginSessionExpiredLive = '(HM%.FppError)', - strRetStatBusy = "(form name=.hotmail.)", - - -- Regular expression to extract the mail server - -- - - -- Extract the server to post the login data to - -- - strLoginPostUrlPattern1='action="([^"]+)"', - strLoginPostUrlPattern2='type=["]?hidden["]? name="([^"]*)".* value="([^"]*)"', - strLoginPostUrlPattern3='g_DO."%s".="([^"]+)"', - strLoginPostUrlPattern4='var g_QS="([^"]+)";', - strLoginPostUrlPattern5='name="PPFT" id="[^"]+" value="([^"]+)"', - strLoginDoneReloadToHMHome1='URL=([^"]+)"', - strLoginDoneReloadToHMHome2='%.location%.replace%("([^"]+)"', - strLoginDoneReloadToHMHome3="location='([^']+)'", --- strLoginDoneReloadToHMHome3='location=.([^"%']+)', - strLoginDoneReloadToHMHome4="img src='([^']+)'", - strLoginDoneReloadToReloadPage='window%.location=\'([^\']+)\'', - - -- Pattern to detect if we are using the live or classic version - -- - strLiveCheckPattern = '(TodayLight%.aspx)', - strClassicCheckPattern = '(Windows Live Mail was not able to sign into your account at this time)', - strLiveMainPagePattern = '<frame.-name="main" src="([^"]+)"', - strLiveLightPagePattern = 'href="(StylesheetTodayLight)', - - -- Get the crumb value that is needed for every command - -- - strRegExpCrumb = '&a=([^"&]*)[&"]', - strRegExpCrumbLive = '"sessionidhash" : "([^"]+)"', - strRegExpUser = '"authuser" : "([^"]+)"', - - -- MSN Inbox Folder Id - -- - strPatMSNInboxId = "HMFO%('(%d+)'%)[^>]+><img src=.http://[^/]+/i.p.folder.inbox.gif", - - -- Image server pattern - -- - strImgServerPattern = 'img src="(http://[^/]*)/spacer.gif"', - strImgServerLivePattern = 'img src="(http://[^/]*)/mail/', - - -- Junk and Trash Folder pattern - -- - strPatLiveTrashId = '"sysfldrtrash".-"([^"]+)"', - strPatLiveJunkId = '"sysfldrjunk".-"([^"]+)"', - - -- Folder id pattern - -- - strFolderPattern = '<a href="[^"]+curmbox=([^&]+)&[^"]+" >', - strFolderLivePattern = '%("([^"]+)","', - strFolderLiveInboxPattern = 'sysfldrinbox".-"([^"]+)"', - strFolderLiveLightInboxPattern = 'href="InboxLight%.aspx%?(FolderID=[^&]+[^"]+)"[^>]+><img src=".-i_inbox.gif"', - strFolderLiveLightFolderIdPattern = 'FolderID=([^&]+)&[.]*', - strFolderLiveLightNPattern = '&n=([^&]+)[.]*', - - strFolderLiveLightTrashPattern = 'i_trash%.gif" border="0" alt=""/></td>.-<td class="dManageFoldersFolderNameCol"><a href="InboxLight%.aspx%?FolderID=([^&]+)&', - strFolderLiveLightJunkPattern = 'i_junkfolder%.gif" border="0" alt=""/></td>.-<td class="dManageFoldersFolderNameCol"><a href="InboxLight%.aspx%?FolderID=([^&]+)&', - strFolderLiveLightPattern = 'href="InboxLight%.aspx%?FolderID=([^&]+)&n=[^"]+" title="', - strFolderLiveLightManageFoldersPattern = 'href="ManageFoldersLight%.aspx%?n=([^"]+)"', - - -- Pattern to determine if we have no messages - -- - strMsgListNoMsgPat = "(<td colspan=10>)", --"(There are no messages in this folder)", - - -- Pattern to determine the total number of messages - -- - strMsgListCntPattern = "<td width=100. align=center>([^<]+)</td><td align=right nowrap>", - strMsgListCntPattern2 = "([%d]+) [MmNnBbVv][eai]", - strMsgListLiveLightCntPattern = '<div class="dItemListHeaderMsgInfo">.- (%d+)</div>', - - -- Used by Stat to pull out the message ID and the size - -- - strMsgLineLitPattern = ".*<tr>.*<td>[.*]{img}.*</td>.*<td>.*<img>.*</td>.*<td>[.*]{img}.*</td>.*<td>.*<input>.*</td>.*<td>.*</td>.*<td>.*<a>.*</a>.*</td>.*<td>.*</td>.*<td>.*</td>.*<td>.*</td>.*</tr>", - strMsgLineAbsPattern = "O<O>O<O>[O]{O}O<O>O<O>O<O>O<O>O<O>[O]{O}O<O>O<O>O<X>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>X<O>O<O>", - - - -- Pattern used by Stat to get the next page in the list of messages - -- - strMsgListNextPagePattern = '(nextpg%.gif" border=0></a>)', - strMsgListNextPagePatLiveLight = '<a href="([^"]+)"[^>]*><img src="[^_]*_nextpage.gif"', - - -- Pattern used to detect a bad STAT page. - -- - strMsgListGoodBody = 'i%.p%.attach%.gif', - - -- Pattern used in the Live interface to get the message info - -- - strMsgLivePatternOld = ',"([^"]+)","[^"]+","[^"]+",[^,]+,[^,]+,[^,]+,[^,]+,"([^"]+)"', - strMsgLivePattern1 = 'class=.-SizeCell.->([^<]+)</div>', - strMsgLivePattern2 = 'new HM%.__[^%(]+%("([^"]+)",[tf][^,"]+,"[^"]+",[^,]+,[^,]+', - strMsgLiveLightPattern = 'ReadMessageId=([^&]+)&[^>]+>.-</a></td>.-<td [^>]+>.-</td>.-<td [^>]+>([^<]+)</td>', - - -- The amount of time that the session should time out at. - -- This is expressed in seconds - -- - nSessionTimeout = 28800, -- 8 hours! - - -- Defined Mailbox names - These define the names to use in the URL for the mailboxes - -- - strNewFolderPattern = "(curmbox=0)", - strFolderPrefix = "00000000-0000-0000-0000-000", - strInbox = "F000000001", - - -- Command URLS - -- - strCmdBaseLive = "http://%s/mail/", - strCmdBrowserIgnoreLive = "http://%s/mail/mail.aspx?skipbrowsercheck=true", - strCmdMsgList = "http://%s/cgi-bin/HoTMaiL?a=%s&curmbox=%s", - strCmdMsgListNextPage = "&page=%d&wo=", - strCmdMsgListLiveLight = "http://%s/mail/InboxLight.aspx?FolderID=%s", - strCmdMsgListLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.MailBox.GetFolderData&ptid=0&a=%s&au=%s", - strCmdMsgListPostLiveOld = "cn=Microsoft.Msn.Hotmail.MailBox&mn=GetFolderData&d=%s,Date,%s,false,0,%s,0,,&MailToken=", - strCmdMsgListPostLive = 'cn=Microsoft.Msn.Hotmail.MailBox&mn=GetFolderData&d=%s,Date,%s,false,0,%s,0,"","",true,false&v=1&mt=%s', - - strCmdDelete = "http://%s/cgi-bin/HoTMaiL", - strCmdDeletePost = "curmbox=%s&_HMaction=delete&wo=&SMMF=0", -- &<MSGID>=on - strCmdDeleteLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.MailBox.MoveMessages&ptid=0&a=%s&au=%s", - strCmdDeletePostLiveOld = 'cn=Microsoft.Msn.Hotmail.MailBox&mn=MoveMessages&d="%s","%s",[%s],[{"%%5C%%7C%%5C%%7C%%5C%%7C0%%5C%%7C%%5C%%7C%%5C%%7C00000000-0000-0000-0000-000000000001%%5C%%7C632901424233870000",{2,"00000000-0000-0000-0000-000000000000",0}}],null,null,0,false,Date&v=1', - -- strCmdDeletePostLive = 'cn=Microsoft.Msn.Hotmail.MailBox&mn=MoveMessages&d="%s","%s",[%s],[{"%%5C%%7C%%5C%%7C%%5C%%7C0%%5C%%7C%%5C%%7C%%5C%%7C%%5C%%7C00000000-0000-0000-0000-000000000001%%5C%%7C632750213035330000",null}],null,null,0,false,Date,false,true&v=1&mt=%s', - strCmdDeletePostLive = 'cn=Microsoft.Msn.Hotmail.MailBox&mn=MoveMessages&d="%s","%s",[%s],[{"0%%5C%%7C0%%5C%%7C8C9BDFF65883200%%5C%%7C00000000-0000-0000-0000-000000000001",null}],null,null,0,false,Date,false,true&v=1&mt=%s', - strCmdDeleteLiveLight = "http://%s/mail/InboxLight.aspx?FolderID=%s&", - strCmdDeletePostLiveLight = "__VIEWSTATE=&mt=%s&MoveMessageSelector=%s&ToolbarActionItem=MoveMessageSelector&", -- SelectedMessages=%s", - strCmdMsgView = "http://%s/cgi-bin/getmsg?msg=%s&imgsafe=y&curmbox=%s&a=%s", - strCmdMsgViewRaw = "&raw=0", - strCmdMsgViewLive = "http://%s/mail/GetMessageSource.aspx?msgid=%s&gs=true", - strCmdEmptyTrash = "http://%s/cgi-bin/dofolders?_HMaction=DoEmpty&curmbox=F000000004&a=%s&i=F000000004", - strCmdLogout = "http://%s/cgi-bin/logout", - strCmdLogoutLive = "http://%s/mail/logout.aspx", - strCmdFolders = "http://%s/cgi-bin/folders?&curmbox=F000000001&a=%s", - strCmdFoldersLiveLight = "http://%s/mail/ManageFoldersLight.aspx?n=%s", - strCmdMsgUnreadLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.MailBox.MarkMessages&ptid=0&a=", - strCmdMsgUnreadLivePost = "cn=Microsoft.Msn.Hotmail.MailBox&mn=MarkMessages&d=false,[%s]", - strCmdEmptyTrashLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.MailBox.EmptyFolder&ptid=0&a=&au=%s", - strCmdEmptyTrashLivePost = "cn=Microsoft.Msn.Hotmail.MailBox&mn=EmptyFolder&d=%s,0", - strCmdEmptyTrashLiveLight = "http://%s/mail/InboxLight.aspx?EmptyFolder=True&FolderID=%s&", - strCmdEmptyTrashLiveLightPost = "__VIEWSTATE=&mt=%s&query=&MoveMessageSelector=&ToolbarActionItem=&InfoPaneActionItem=EmptyFolderConfirmYes", - strCmdMsgReadLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.MailBox.MarkMessages&ptid=0&a=&au=%s", - strCmdMsgReadLivePost = "cn=Microsoft.Msn.Hotmail.MailBox&mn=MarkMessages&d=true,[%s]&v=1&mt=%s", - strCmdMsgReadLiveLight = "http://%s/mail/ReadMessageLight.aspx?AllowUnsafe=True&Aux=&FolderID=%s&InboxSortAscending=False&InboxSortBy=Date&ReadMessageId=%s", -} - --- ************************************************************************** -- --- State - Declare the internal state of the plugin. It will be serialized and remembered. --- ************************************************************************** -- - -internalState = { - bStatDone = false, - bLoginDone = false, - strUser = nil, - strPassword = nil, - browser = nil, - strMailServer = nil, - strImgServer = nil, - strDomain = nil, - strCrumb = "", - strMBox = nil, - strMBoxName = nil, - bEmptyTrash = false, - bEmptyJunk = false, - loginTime = nil, - bMarkMsgAsUnread = false, - bLiveGUI = false, - bLiveLightGUI = false, - strTrashId = nil, - strJunkId = nil, - statLimit = nil, - strUserId = "", - strMT = "", -} - --- ************************************************************************** -- --- Debugging functions --- ************************************************************************** -- - --- Set to true to enable Raw Logging --- -local ENABLE_LOGRAW = false - --- The platform dependent End Of Line string --- e.g. this should be changed to "\n" under UNIX, etc. -local EOL = "\r\n" - --- The raw logging function --- -log = log or {} -- fast hack to make the xml generator happy -log.raw = function ( line, data ) - if not ENABLE_LOGRAW then - return - end - - local out = assert(io.open("log_raw.txt", "ab")) - out:write( EOL .. os.date("%c") .. " : " ) - out:write( line ) - if data ~= nil then - out:write( EOL .. "--------------------------------------------------" .. EOL ) - out:write( data ) - out:write( EOL .. "--------------------------------------------------" ) - end - assert(out:close()) -end - - --- ************************************************************************** -- --- Helper functions --- ************************************************************************** -- - --- Serialize the state --- --- serial. serialize is not enough powerfull to correcly serialize the --- internal state. the problem is the field b. b is an object. this means --- that is a table (and no problem for this) that has some field that are --- pointers to functions. this is the problem. there is no easy way for the --- serial module to know how to serialize this. so we call b:serialize --- method by hand hacking a bit on names --- -function serialize_state() - internalState.bStatDone = false; - - return serial.serialize("internalState", internalState) .. - internalState.browser:serialize("internalState.browser") -end - --- Computes the hash of our state. Concate the user, domain, mailbox and password --- -function hash() - return (internalState.strUser or "") .. "~" .. - (internalState.strDomain or "") .. "~" .. - (internalState.strMBoxName or "") .. "~" .. - (internalState.statLimit or "") .. "~" .. - internalState.strPassword -- this asserts strPassword ~= nil -end - -function getPage(browser, url) - local try = 0 - while (try < 3) do - local body, err = browser:get_uri(url) - - if (body == nil) then - log.raw("Tried to load: " .. url .. " and got error: " .. err) - elseif (string.find(body, "We are experiencing higher than normal volume") == nil and - string.find(body, "<[Hh][Tt][Mm][Ll]") ~= nil and - string.find(body, "MSN Hotmail %- ERROR") == nil) then - return body, err - end - try = try + 1 - local newurl = string.match(body, 'Object moved to <a href="([^"]+)"') - if (newurl ~= nil) then - return getPage(browser, newurl) - end - if (body ~= nil) then - log.raw("Attempt to load: " .. url .. " failed in attempt: " .. try) - end - end - - return nil, nil -end - --- Issue the command to login to Hotmail --- -function loginHotmail() - log.raw("Entering login") - - -- Check to see if we've already logged in - -- - if internalState.loginDone then - return POPSERVER_ERR_OK - end - - -- Create a browser to do the dirty work - -- - internalState.browser = browser.new("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727") - - -- Define some local variables - -- - local username = internalState.strUser - local password = internalState.strPassword --curl.escape(internalState.strPassword) - local passwordlen = string.len(internalState.strPassword) - local domain = internalState.strDomain - local url = globals.strLoginUrl - local browser = internalState.browser - local postdata = nil - local name, value - - -- DEBUG - Set the browser in verbose mode - -- --- browser:verbose_mode() - - -- Enable SSL - -- - browser:ssl_init_stuff() - - -- Retrieve the login page. - -- - local body, err = getPage(browser, url) - - -- No connection - -- - if body == nil then - log.error_print("Login Failed: Unable to make connection") - log.raw("Login failed: Can't get the page: " .. url .. ", Error: " .. (err or "none")); - return POPSERVER_ERR_NETWORK - end - - -- Hotmail will return with the login page. This page supports a slew of domains. - -- Pull out the place where we need to post the login information. Post the form - -- to login. - -- - local pattern = string.format(globals.strLoginPostUrlPattern3, domain) - url = string.match(body, pattern) - local str = string.match(body, globals.strLoginPostUrlPattern4) - local str2 = string.match(body, globals.strLoginPostUrlPattern5) - if (str == nil or str2 == nil) then - log.error_print(globals.strLoginFailed) - return POPSERVER_ERR_NETWORK - end - if (url == nil) then - url = globals.strDefaultLoginPostUrl - end - url = url .. "?" .. str - - local padding = string.sub(globals.strLoginPaddingFull, 0, globals.nMaxPasswordLen - passwordlen) - postdata = string.format(globals.strLoginPostData, username, domain, curl.escape(password), padding) - postdata = postdata .. "&PPFT=" .. str2 - - log.dbg("Hotmail - Sending login information to: " .. url) - body, err = browser:post_uri(url, postdata) - if (body == nil) then - log.error_print(globals.strLoginFailed) - log.raw("Login failed: Sent login info to: " .. (url or "none") .. " and got something we weren't expecting(0):\n" .. err); - return POPSERVER_ERR_NETWORK - end - - -- The login page returns a page where a form needs to be submitted. We'll do it - -- manually. Extract the form elements and post the data - -- - url = string.match(body, globals.strLoginPostUrlPattern1) - local postdata = nil - local name, value - for name, value in string.gfind(body, globals.strLoginPostUrlPattern2) do - value = curl.escape(value) - if postdata ~= nil then - postdata = postdata .. "&" .. name .. "=" .. value - else - postdata = name .. "=" .. value - end - end - if (postdata ~= nil) then - body, err = browser:post_uri(url, postdata) - end - - -- We should be logged in now! Unfortunately, we aren't done. Hotmail returns a page - -- that should auto-reload in a browser but not in curl. It's the URL for Hotmail Today. - -- - url = string.match(body, globals.strLoginDoneReloadToHMHome1) - if url == nil then - url = string.match(body, globals.strLoginDoneReloadToHMHome2) - if url == nil then - log.error_print(globals.strLoginFailed) - log.raw("Login failed: Sent login info to: " .. (url or "none") .. " and got something we weren't expecting(1):\n" .. body); - return POPSERVER_ERR_NETWORK - end - end - - str = string.match(url, globals.strRetLoginBadLogin) - if str ~= nil then - log.error_print(globals.strLoginFailed) - log.raw("Login failed: Sent login info to: " .. (url or "none") .. " and got something we weren't expecting(2):\n" .. body); - return POPSERVER_ERR_NETWORK - end - body, err = getPage(browser, url) - - -- Shouldn't happen but you never know - -- - if body == nil then - log.error_print(globals.strLoginFailed) - return POPSERVER_ERR_NETWORK - end - - -- Check to see if we are using a classic account - -- - local str = string.match(body, globals.strClassicCheckPattern) - if str ~= nil then - log.dbg("Hotmail: Detected Classic version.") - body, err = browser:get_uri("http://www.hotmail.com") - end - - -- Check to see if we are using the new interface and are redirecting. - -- - str = string.match(body, globals.strLiveCheckPattern) - local folderBody = body - if str ~= nil then - log.dbg("Hotmail: Detected LIVE version.") - str = string.format(globals.strCmdBrowserIgnoreLive, browser:wherearewe()) - body, err = browser:get_uri(str) - str = string.match(body, globals.strLiveMainPagePattern) - if str ~= nil then - str = string.format(globals.strCmdBaseLive, browser:wherearewe()) .. str - body, err = browser:get_uri(str) - else - str = string.match(body, globals.strLiveLightPagePattern) - if (str ~= nil) then - log.dbg("Hotmail: Detected LIVE version is in LIGHT mode.") - internalState.bLiveLightGUI = true - else - log.error_print(globals.strLoginFailed) - log.raw("Login failed: Trying to get session id and got something we weren't expecting:\n" .. body); - return POPSERVER_ERR_NETWORK - end - end - - internalState.bLiveGUI = true - else - -- One or two more redirects - -- - local oldurl = url - url = string.match(body, globals.strLoginDoneReloadToReloadPage) - if url ~= nil then - body, err = browser:get_uri(url) - end - url = string.match(body, globals.strLoginDoneReloadToHMHome1) - if url == nil then - url = string.match(body, globals.strLoginDoneReloadToHMHome2) - if url == nil then - -- Change suggested by 930 - local authimgurl = string.match(body, globals.strLoginDoneReloadToHMHome4) - if authimgurl ~= nil then - browser:get_uri(authimgurl) - end - url = string.match(body, globals.strLoginDoneReloadToHMHome3) - if url == nil then - log.error_print(globals.strLoginFailed) - log.raw("Login failed: Sent login info to: " .. (oldurl or "none") .. " and got something we weren't expecting(3):\n" .. body); - return POPSERVER_ERR_NETWORK - end - -- End change - end - end - body, err = browser:get_uri(url) - end - - -- Extract the crumb - This is needed for deletion of items - -- - if (internalState.bLiveLightGUI ~= true) then - local user = nil - if (internalState.bLiveGUI == true) then - str = string.match(body, globals.strRegExpCrumbLive) - user = string.match(body, globals.strRegExpUser) - else - str = string.match(body, globals.strRegExpCrumb) - end - - if str == nil then - log.error_print("Can't get the 'a' value. This will lead to problems!") - internalState.strCrumb = "" - else - internalState.strCrumb = str - - -- Debug Message - -- - log.dbg("Hotmail Crumb value: " .. str .. "\n") - end - - if user == nil then - log.error_print("Can't get the 'authuser' value. This will lead to problems!") - internalState.strUserId = "" - else - internalState.strUserId = user - - -- Debug Message - -- - log.dbg("Hotmail Authuser value: " .. user .. "\n") - end - end - - -- Get the MT cookie value - -- - local cookie = browser:get_cookie('mt') - if (cookie ~= nil) then - internalState.strMT = cookie.value - log.dbg("Hotmail mt value: " .. cookie.value) - end - - -- Save the mail server - -- - internalState.strMailServer = browser:wherearewe() - - -- DEBUG Message - -- - log.dbg("Hotmail Server: " .. internalState.strMailServer .. "\n") - - -- Find the image server - -- - if (internalState.bLiveGUI == true) then - str = string.match(body, globals.strImgServerLivePattern) - else - str = string.match(body, globals.strImgServerPattern) - end - - if str ~= nil then - internalState.strImgServer = str - log.dbg("Hotmail image server: " .. str) - else - internalState.strImgServer = internalState.strMailServer - log.dbg("Couldn't figure out the image server. Using the mail server as a default.") - log.raw("Login failed: Should be logged in right now but am not. Last page loaded: " .. url .. " with body:\n" .. body); - end - - -- Note the time when we logged in - -- - internalState.loginTime = os.clock(); - - -- If we haven't set the folder yet, then it is a custom one and we need to grab it - -- - internalState.strMBoxName = string.gsub(internalState.strMBoxName, '%-', "%%-") - if (internalState.strMBox == nil and internalState.bLiveGUI == false) then - local url = string.format(globals.strCmdFolders, internalState.strMailServer, - internalState.strCrumb) - body, err = browser:get_uri(url) - str = string.match(body, globals.strFolderPattern .. internalState.strMBoxName .. "</a>") - if (str == nil and domain == "msn.com" and internalState.strMBoxName == "Inbox") then - str = string.match(body, globals.strPatMSNInboxId) - end - if (str == nil) then - log.error_print("Unable to figure out folder id with name: " .. internalState.strMBoxName) - return POPSERVER_ERR_NETWORK - else - internalState.strMBox = str - log.dbg("Hotmail - Using folder (" .. internalState.strMBox .. ")") - end - elseif (internalState.bLiveGUI == true and internalState.bLiveLightGUI == false) then - -- Get some folder id's - -- - local inboxId = string.match(body, globals.strFolderLiveInboxPattern) - - -- Get the trash folder id and the junk folder id - -- - str = string.match(body, globals.strPatLiveTrashId) - if str ~= nil then - internalState.strTrashId = str - log.dbg("Hotmail - trash folder id: " .. str) - else - log.error_print("Unable to detect the folder id for the trash folder. Deletion may fail.") - end - - str = string.match(body, globals.strPatLiveJunkId) - if str ~= nil then - internalState.strJunkId = str - log.dbg("Hotmail - junk folder id: " .. str) - else - log.error_print("Unable to detect the folder id for the junk folder. Deletion may fail.") - end - - if (internalState.strMBoxName == "Inbox") then - str = inboxId - elseif (internalState.strMBoxName == "Junk" or internalState.strMBoxName == "Junk E%-Mail") then - str = internalState.strJunkId - else - str = getFolderId(inboxId) - end - - if (str == nil) then - log.error_print("Unable to figure out folder id with name: " .. internalState.strMBoxName) - return POPSERVER_ERR_NETWORK - else - internalState.strMBox = str - log.dbg("Hotmail - Using folder (" .. internalState.strMBox .. ")") - end - elseif (internalState.bLiveGUI == true and internalState.bLiveLightGUI == true) then - -- cdmackie: Live Light has an "n" value in the folders list that we need to get - local n = string.match(body, globals.strFolderLiveLightManageFoldersPattern) - local url = string.format(globals.strCmdFoldersLiveLight, internalState.strMailServer, n) - - body, err = browser:get_uri(url) - - -- cdmackie: we then extract the querystring and apend the InboxId with the N value - local inboxQueryString = string.match(body, globals.strFolderLiveLightInboxPattern) - local inboxId = string.match(inboxQueryString, globals.strFolderLiveLightFolderIdPattern) - local inboxN = string.match(inboxQueryString, globals.strFolderLiveLightNPattern) - inboxId = inboxId .. "&n=" .. inboxN - - if (internalState.strMBoxName == "Inbox") then - str = inboxId - else - str = string.match(body, globals.strFolderLiveLightPattern .. internalState.strMBoxName) - end - - if (str == nil) then - log.error_print("Unable to figure out folder id with name: " .. internalState.strMBoxName) - return POPSERVER_ERR_NETWORK - else - internalState.strMBox = str - log.dbg("Hotmail - Using folder (" .. internalState.strMBox .. ")") - end - - -- Get the trash folder id and the junk folder id - -- - str = string.match(body, globals.strFolderLiveLightTrashPattern) - if str ~= nil then - internalState.strTrashId = str - log.dbg("Hotmail - trash folder id: " .. str) - else - log.error_print("Unable to detect the folder id for the trash folder. Deletion may fail.") - end - - str = string.match(body, globals.strFolderLiveLightJunkPattern) - if str ~= nil then - internalState.strJunkId = str - log.dbg("Hotmail - junk folder id: " .. str) - else - log.error_print("Unable to detect the folder id for the junk folder. Deletion may fail.") - end - end - - -- Note that we have logged in successfully - -- - internalState.bLoginDone = true - - -- Debug info - -- - log.dbg("Created session for " .. - internalState.strUser .. "@" .. internalState.strDomain .. "\n") - - -- Return Success - -- - log.raw("Successful login") - return POPSERVER_ERR_OK -end - -function getFolderId(inboxId) - local cmdUrl = string.format(globals.strCmdMsgListLive, internalState.strMailServer, - internalState.strCrumb, internalState.strUserId) - local post = string.format(globals.strCmdMsgListPostLive, inboxId, 0, 0, internalState.strMT) - local body, err = internalState.browser:post_uri(cmdUrl, post) - local str = string.match(body, globals.strFolderLivePattern .. internalState.strMBoxName .. '","i_') - return str -end - --- Download a single message --- -function downloadMsg(pstate, msg, nLines, data) - -- Make sure we aren't jumping the gun - -- - local retCode = stat(pstate) - if retCode ~= POPSERVER_ERR_OK then - return retCode - end - - -- Local Variables - -- - local browser = internalState.browser - local uidl = get_mailmessage_uidl(pstate, msg) - - local url = string.format(globals.strCmdMsgView, internalState.strMailServer, - uidl, internalState.strMBox, internalState.strCrumb); - local markReadUrl = url - url = url .. globals.strCmdMsgViewRaw - if (internalState.bLiveGUI == true) then - url = string.format(globals.strCmdMsgViewLive, internalState.strMailServer, uidl) - end - - -- Debug Message - -- - log.dbg("Getting message: " .. uidl .. ", URL: " .. url) - - -- Define a structure to pass between the callback calls - -- - local cbInfo = { - -- Whether this is the first call of the callback - -- - bFirstBlock = true, - nAttempt = 0, - bRetry = true, - - -- String hacker - -- - strHack = stringhack.new(), - - -- Lines requested (-2 means not limited) - -- - nLinesRequested = nLines, - - -- Lines Received - Not really used for anything - -- - nLinesReceived = 0, - - -- Buffer - -- - strBuffer = "", - - -- addition - cb_uidl = uidl, -- to provide the uidl for later... - bEndReached = false -- this is a hack, I know... - -- end of addition - } - - -- Define the callback - -- - local cb = downloadMsg_cb(cbInfo, data) - - -- Start the download on the body - -- - while (cbInfo.bRetry == true and cbInfo.nAttempt < 3) do - local f, err = browser:pipe_uri(url, cb) - if err then - -- Log the error - -- - log.raw("Message: " .. cbInfo.cb_uidl .. " received error: " .. err) - end - end - if (cbInfo.bRetry == true) then - log.error_print("Message: " .. cbInfo.cb_uidl .. " failed to download.") - log.raw("Message: " .. cbInfo.cb_uidl .. " failed to download.") - return POPSERVER_ERR_NETWORK - end - - -- Handle whatever is left in the buffer - -- - local body = cbInfo.strBuffer - if (string.len(body) > 0 and cbInfo.nLinesRequested == -2) then - log.raw("Message: " .. cbInfo.cb_uidl .. ", left over buffer being processed: " .. body) - body = cleanupBody(body, cbInfo) - - -- cdmackie: rather than test for </pre> to determine end, just set it seen - -- as we've reached end of buffer..and hotmail doesn't always send "</pre>" - cbInfo.bEndReached = true - cbInfo.nLinesReceived = -1; - -- apply same fixup from cleanupbody to remove dead tags - if (string.len(body) > 6) then - local idx = string.find(string.sub(body, -6), "([&<])") - if (idx ~= nil) then - idx = idx - 1 - cbInfo.strBuffer = string.sub(body, -6 + idx) - local len = string.len(body) - 6 + idx - body = string.sub(body, 1, len) - end - end - -- make sure we end in a crlf - if (string.sub(body, -2, -1) ~= "\r\n") then - body = body .. "\r\n" - end - - if (cbInfo.bEndReached == false) then - log.dbg("Forcing a CRLF to end the message as it isn't clear the message is ended properly") - popserver_callback("\r\n\0", data) - end - body = cbInfo.strHack:dothack(body) .. "\0" - popserver_callback(body, data) - elseif (cbInfo.bEndReached == false and cbInfo.nLinesRequested == -2) then - popserver_callback("\r\n\0", data) - end - - -- Mark the message as read - -- - if internalState.bMarkMsgAsUnread == false and internalState.bLiveGUI == false then - log.raw("Message: " .. cbInfo.cb_uidl .. ", Marking message as being done.") - browser:get_head(markReadUrl) - elseif internalState.bMarkMsgAsUnread == false and internalState.bLiveGUI and internalState.bLiveLightGUI == false then - log.raw("Message: " .. cbInfo.cb_uidl .. ", Marking message as read.") - url = string.format(globals.strCmdMsgReadLive, internalState.strMailServer, internalState.strUserId) - local post = string.format(globals.strCmdMsgReadLivePost, uidl, internalState.strMT) - browser:post_uri(url, post) - elseif internalState.bMarkMsgAsUnread == false and internalState.bLiveGUI and internalState.bLiveLightGUI then - log.raw("Message: " .. cbInfo.cb_uidl .. ", Marking message as read.") - url = string.format(globals.strCmdMsgReadLiveLight, internalState.strMailServer, internalState.strMBox, uidl) - browser:get_head(url) - elseif internalState.bMarkMsgAsUnread == true and internalState.bLiveGUI == true then - log.raw("Message: " .. cbInfo.cb_uidl .. ", Marking message as unread.") - url = string.format(globals.strCmdMsgUnreadLive, internalState.strMailServer) - local post = string.format(globals.strCmdMsgUnreadLivePost, uidl) - browser:post_uri(url, post) - end - - log.raw("Message: " .. cbInfo.cb_uidl .. ", Completed!") - return POPSERVER_ERR_OK -end - --- Callback for the retr function --- -function downloadMsg_cb(cbInfo, data) - - return function(body, len) - log.raw("In download callback: " .. cbInfo.cb_uidl) - - -- Is this the first block? If so, make sure we have a valid message - -- - if (cbInfo.bFirstBlock == true) then - if (string.find(body, "<pre>")) then - cbInfo.bRetry = false - log.raw("Message: " .. cbInfo.cb_uidl .. " was loaded successfully.") - else - cbInfo.bRetry = true - cbInfo.nAttempt = cbInfo.nAttempt + 1 - log.raw("Message: " .. cbInfo.cb_uidl .. " failed on attempt: " .. cbInfo.nAttempt .. ", Body: " .. body) - log.raw("out download callback: " .. cbInfo.cb_uidl) - return 0, nil - end - end - - -- Are we done with Top and should just ignore the chunks - -- - if (cbInfo.nLinesReceived == -1) then - log.raw("out download callback: " .. cbInfo.cb_uidl .. ", Sent: <Nothing>") - return 0, nil - end - - -- Update the buffer - -- - body = cbInfo.strBuffer .. body - cbInfo.strBuffer = "" - if (string.len(body) > 6) then - local idx = string.find(string.sub(body, -6), "([&<])") - if (idx ~= nil) then - idx = idx - 1 - cbInfo.strBuffer = string.sub(body, -6 + idx) - local len = string.len(body) - 6 + idx - body = string.sub(body, 1, len) - end - end - - body = cleanupBody(body, cbInfo) - - -- Perform our "TOP" actions - -- - if (cbInfo.nLinesRequested ~= -2) then - body = cbInfo.strHack:tophack(body, cbInfo.nLinesRequested) - - -- Check to see if we are done and if so, update things - -- - if cbInfo.strHack:check_stop(cbInfo.nLinesRequested) then - cbInfo.nLinesReceived = -1; - if (string.sub(body, -2, -1) ~= "\r\n") then - body = body .. "\r\n" - end - else - cbInfo.nLinesReceived = cbInfo.nLinesRequested - - cbInfo.strHack:current_lines() - end - end - - -- End the strings properly - -- - body = cbInfo.strHack:dothack(body) .. "\0" - - -- Send the data up the stream - -- - popserver_callback(body, data) - - log.raw("out download callback: " .. cbInfo.cb_uidl .. ", Sent: " .. body) - return len, nil - end -end - -function cleanupHeaders(headers, cbInfo) - -- Cleanup the headers. They are HTML-escaped. - -- - local origHeaders = headers - local bMissingTo = false -- it seems hotmail server sometimes disregards To: when 'raw=0' ? - -- probably only in internal HoTMaiL-service letters, where the actual - -- internet message headers do not contain actual To:-field - local bMissingID = false -- when no Message-ID -field seems to have been automatically generated ? - local bodyrest = "" - - headers, bodyrest = string.match(headers, "^(.-)\r*\n%s*\r*\n(.*)$" ) - - if (headers == nil) then - log.dbg("Hotmail: unable to parse out message headers. Extra headers will not be used.") - return origHeaders - end - - headers = string.gsub(headers, "%s+$", "\n") - headers = headers .. "\n"; - headers = string.gsub(headers, "\n\n", "\n") - headers = string.gsub(headers, "\r\n", "\n") - headers = string.gsub(headers, "\n", "\r\n") - - -- - -- some checking... - -- - if string.find(headers, "(To:)") == nil then - bMissingTo = true - end - if string.find(headers, "(Message%-I[dD]:)") == nil then - bMissingID = true - end - - -- Add some headers - -- - if bMissingTo ~= false then - headers = headers .. "To: " .. internalState.strUser .. "@" .. internalState.strDomain .. "\r\n" ; - end - - if bMissingID ~= false then - local msgid = cbInfo.cb_uidl .. "@" .. internalState.strMailServer -- well, if we do not have any better choice... - headers = headers .. "Message-ID: <" .. msgid .. ">\r\n" - end - - headers = headers .. "X-FreePOPs-User: " .. internalState.strUser .. "@" .. internalState.strDomain .. "\r\n" - headers = headers .. "X-FreePOPs-Domain: " .. internalState.strDomain .. "\r\n" - headers = headers .. "X-FreePOPs-Folder: " .. internalState.strMBox .. "\r\n" - headers = headers .. "X-FreePOPs-MailServer: " .. internalState.strMailServer .. "\r\n" - headers = headers .. "X-FreePOPs-ImageServer: " .. internalState.strImgServer .. "\r\n" - headers = headers .. "X-FreePOPs-MsgNumber: " .. "<" .. cbInfo.cb_uidl .. ">" .. "\r\n" - - -- make the final touch... - -- - headers = headers .. "\r\n" .. bodyrest - - return headers -end - -function cleanupBody(body, cbInfo) - -- check to see whether the end of message has already been seen... - -- - if (cbInfo.bEndReached == true) then - return ("") ; -- in this case we pass nothing past the end of message - end - - -- Did we reach the end of the message - -- - -- cdmackie: test for the end after we've processed the buffers instead - -- GetMessageSource sometimes returns only "</" instead of "</pre>" - --if (string.find(body, "(</pre>)") ~= nil) then - -- cbInfo.nLinesReceived = -1; - -- cbInfo.bEndReached = true - --end - - -- The only parts we care about are within <pre>..</pre> - -- - body = string.gsub(body, "<pre>[%s]*", "") - body = string.gsub(body, "</pre>.-$", "\n") - - -- Clean up the end of line, and replace HTML tags - -- - body = string.gsub(body, "	", "\t") - body = string.gsub(body, "	", "\t") - body = string.gsub(body, " ", "\n") - body = string.gsub(body, " ", "\r") - body = string.gsub(body, " ", " ") - body = string.gsub(body, "!", "!") - body = string.gsub(body, "#", "#") - body = string.gsub(body, "$", "$") - -- cdmackie: this should be escaped - body = string.gsub(body, "%", "%%") - body = string.gsub(body, "&", "&") - body = string.gsub(body, "'", "'") - body = string.gsub(body, "(", "(") - body = string.gsub(body, ")", ")") - body = string.gsub(body, "*", "*") - body = string.gsub(body, "+", "+") - body = string.gsub(body, ",", ",") - body = string.gsub(body, "-", "-") - body = string.gsub(body, ".", ".") - body = string.gsub(body, "/", "/") - body = string.gsub(body, ":", ":") - body = string.gsub(body, ";", ";") - body = string.gsub(body, "<", "<") - - -- cdmackie: these mess up QP and b64 encoded attachments - --body = string.gsub(body, "=2E", ".") - --body = string.gsub(body, "=3D", "=") - --body = string.gsub(body, "=20", " ") - --body = string.gsub(body, "=09", "\t") - --body = string.gsub(body, "=96", "-") - --body = string.gsub(body, "=\r\n", "") - --body = string.gsub(body, "=92", "'") - - body = string.gsub(body, "=", "=") - body = string.gsub(body, ">", ">") - body = string.gsub(body, "?", "?") - body = string.gsub(body, "@", "@") - body = string.gsub(body, "[", "[") - body = string.gsub(body, "\", "\\") - body = string.gsub(body, "]", "]") - body = string.gsub(body, "^", "^") - body = string.gsub(body, "_", "_") - body = string.gsub(body, "`", "`") - body = string.gsub(body, "{", "{") - body = string.gsub(body, "|", "|") - body = string.gsub(body, "}", "}") - body = string.gsub(body, "~", "~") - - body = string.gsub(body, "\r", "") - body = string.gsub(body, "\n", "\r\n") - -- cdmackie: these mess up QP attachments - --body = string.gsub(body, "&", "&") - --body = string.gsub(body, "<", "<") - --body = string.gsub(body, ">", ">") - --body = string.gsub(body, """, "\"") - body = string.gsub(body, """, "\"") - --body = string.gsub(body, " ", " ") - body = string.gsub(body, "<!%-%-%$%$imageserver%-%->", internalState.strImgServer) - - -- cdmackie: POP protocol: lines starting with a dot must be escaped dotdot - body = string.gsub(body, "\r\n%.", "\r\n%.%.") - - -- We've now at least seen one block, attempt to clean up the headers - -- - if (cbInfo.bFirstBlock == true) then - cbInfo.bFirstBlock = false - body = cleanupHeaders(body, cbInfo) - end - - return body -end - --- ************************************************************************** -- --- Pop3 functions that must be defined --- ************************************************************************** -- - --- Extract the user, domain and mailbox from the username --- -function user(pstate, username) - -- Get the user, domain, and mailbox - -- TODO: mailbox - for now, just inbox - -- - local domain = freepops.get_domain(username) - local user = freepops.get_name(username) - - internalState.strDomain = domain - internalState.strUser = user - - -- Override the domain variable if it is set in the login parameter - -- - local val = (freepops.MODULE_ARGS or {}).domain or nil - if val ~= nil then - log.dbg("Hotmail: Using overridden domain: " .. val) - internalState.strDomain = val - end - - -- If the flag emptyTrash is set to 1 , - -- the trash will be emptied on 'quit' - -- - local val = (freepops.MODULE_ARGS or {}).emptytrash or 0 - if val == "1" then - log.dbg("Hotmail: Trash folder will be emptied on exit.") - internalState.bEmptyTrash = true - end - - -- If the flag emptyjunk is set to 1 , - -- the trash will be emptied on 'quit' - -- - local val = (freepops.MODULE_ARGS or {}).emptyjunk or 0 - if val == "1" then - log.dbg("Hotmail: Junk folder will be emptied on exit.") - internalState.bEmptyJunk = true - end - - -- If the flag markunread=1 is set, then we will mark all messages - -- that we pull as unread when done. - -- - local val = (freepops.MODULE_ARGS or {}).markunread or 0 - if val == "1" then - log.dbg("Hotmail: All messages pulled will be marked unread.") - internalState.bMarkMsgAsUnread = true - end - - -- If the flag maxmsgs is set, - -- STAT will limit the number of messages to the flag - -- - val = (freepops.MODULE_ARGS or {}).maxmsgs or 0 - if tonumber(val) > 0 then - log.dbg("Hotmail: A max of " .. val .. " messages will be downloaded.") - internalState.statLimit = tonumber(val) - end - - -- Get the folder - -- - local mbox = (freepops.MODULE_ARGS or {}).folder - if mbox == nil then - internalState.strMBoxName = "Inbox" - return POPSERVER_ERR_OK - else - mbox = curl.unescape(mbox) - internalState.strMBoxName = mbox - log.say("Using Custom mailbox set to: " .. internalState.strMBoxName .. ".\n") - end - - return POPSERVER_ERR_OK -end - --- Perform login functionality --- -function pass(pstate, password) - -- Store the password - -- - -- truncate password if longer than nMaxPasswordLen characters to mimic broken web page behavior - if string.len(password) > globals.nMaxPasswordLen then - password = string.sub(password, 0, globals.nMaxPasswordLen) - end - - internalState.strPassword = password - - -- Get a session - -- - local sessID = session.load_lock(hash()) - - -- See if we already have a session. We want to prevent - -- multiple sessions for a given account - -- - if sessID ~= nil then - -- Session exists - -- This code is copied from example. It doesn't make sense to me. - -- - - -- Check to see if it is locked - -- Why "\a"? - -- - if sessID == "\a" then - log.dbg("Error: Session locked - Account: " .. internalState.strUser .. - "@" .. internalState.strDomain .. "\n") - return POPSERVER_ERR_LOCKED - end - - -- Load the session which looks to be a function pointer - -- - local func, err = loadstring(sessID) - if not func then - log.error_print("Unable to load saved session (Account: " .. - internalState.strUser .. "@" .. internalState.strDomain .. "): ".. err) - return loginHotmail() - end - - log.dbg("Session loaded - Account: " .. internalState.strUser .. - "@" .. internalState.strDomain .. "\n") - - -- Execute the function saved in the session - -- - func() - - return POPSERVER_ERR_OK - else - -- Create a new session by logging in - -- - return loginHotmail() - end -end - --- Quit abruptly --- -function quit(pstate) - session.unlock(hash()) - return POPSERVER_ERR_OK -end - --- Update the mailbox status and quit --- -function quit_update(pstate) - -- Make sure we aren't jumping the gun - -- - local retCode = stat(pstate) - if retCode ~= POPSERVER_ERR_OK then - return retCode - end - - -- Local Variables - -- - local browser = internalState.browser - local cmdUrl = string.format(globals.strCmdDelete, internalState.strMailServer) - local cnt = get_popstate_nummesg(pstate) - local dcnt = 0 - local postBase = string.format(globals.strCmdDeletePost, internalState.strMBox) - local post = postBase - local uidls = "" - local uidlsLight = "" - - -- Cycle through the messages and see if we need to delete any of them - -- - for i = 1, cnt do - if internalState.bLiveGUI == false and get_mailmessage_flag(pstate, i, MAILMESSAGE_DELETE) then - dcnt = dcnt + 1 - post = post .. "&" .. get_mailmessage_uidl(pstate, i) .. "=on" - - -- Send out in a batch of 5 - -- - if math.mod(dcnt, 5) == 0 then - log.dbg("Sending Delete URL: " .. cmdUrl .. "Post Data: " .. post .. "\n") - local body, err = browser:post_uri(cmdUrl, post) - if not body or err then - log.error_print("Unable to delete messages.\n") - end - - -- Reset the variables - -- - dcnt = 0 - post = postBase - end - elseif internalState.bLiveGUI == true and internalState.bLiveLightGUI and get_mailmessage_flag(pstate, i, MAILMESSAGE_DELETE) then - -- cdmackie: uidlsLight should be appended for multiple messages - uidlsLight = uidlsLight .. "SelectedMessages=" .. get_mailmessage_uidl(pstate, i) .. "&" - dcnt = dcnt + 1 - elseif internalState.bLiveGUI == true and get_mailmessage_flag(pstate, i, MAILMESSAGE_DELETE) then - if i > 1 then - uidls = uidls .. "," .. get_mailmessage_uidl(pstate, i) - else - uidls = get_mailmessage_uidl(pstate, i) - end - dcnt = dcnt + 1 - end - end - - -- Send whatever is left over - -- - if dcnt > 0 and internalState.bLiveGUI == false then - log.dbg("Sending Delete URL: " .. cmdUrl .. "Post Data: " .. post .. "\n") - local body, err = browser:post_uri(cmdUrl, post) - if not body or err then - log.error_print("Unable to delete messages.\n") - end - elseif dcnt > 0 and internalState.bLiveGUI and internalState.bLiveLightGUI == true then - cmdUrl = string.format(globals.strCmdDeleteLiveLight, internalState.strMailServer, internalState.strMBox) - post = string.format(globals.strCmdDeletePostLiveLight, internalState.strMT, - internalState.strTrashId) .. uidlsLight - log.dbg("Sending Trash url: " .. cmdUrl .. " - " .. post) - local body, err = browser:post_uri(cmdUrl, post) - elseif dcnt > 0 and internalState.bLiveGUI then - cmdUrl = string.format(globals.strCmdDeleteLive, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) - uidls = string.gsub(uidls, ",", '","') - uidls = '"' .. uidls .. '"' - post = string.format(globals.strCmdDeletePostLive, internalState.strMBox, - internalState.strTrashId, uidls, internalState.strMT) - log.dbg("Sending Trash url: " .. cmdUrl .. " - " .. post) - local body, err = browser:post_uri(cmdUrl, post) - if (body == nil) then -- M7 Only - DELETE SOON! - post = string.format(globals.strCmdDeletePostLiveOld, internalState.strMBox, - internalState.strTrashId, uidls) - local body, err = browser:post_uri(cmdUrl, post) - end - end - - -- Empty the trash - -- - if internalState.bEmptyTrash and internalState.bLiveGUI == false then - if internalState.strCrumb ~= '' then - cmdUrl = string.format(globals.strCmdEmptyTrash, internalState.strMailServer,internalState.strCrumb) - log.dbg("Sending Empty Trash URL: " .. cmdUrl .."\n") - local body, err = getPage(browser, cmdUrl) - if not body or err then - log.error_print("Error when trying to empty the trash with url: ".. cmdUrl .."\n") - end - else - log.error_print("Cannot empty trash - crumb not found\n") - end - elseif internalState.bEmptyTrash and internalState.bLiveGUI and internalState.bLiveLightGUI == true then - cmdUrl = string.format(globals.strCmdEmptyTrashLiveLight, internalState.strMailServer, internalState.strTrashId) - local post = string.format(globals.strCmdEmptyTrashLiveLightPost, internalState.strMT) - log.dbg("Sending Empty Trash URL: " .. cmdUrl .."\n") - local body, err = browser:post_uri(cmdUrl, post) - if not body or err then - log.error_print("Error when trying to empty the trash with url: ".. cmdUrl .."\n") - end - elseif internalState.bEmptyTrash and internalState.bLiveGUI then - cmdUrl = string.format(globals.strCmdEmptyTrashLive, internalState.strMailServer, internalState.strUserId) - local post = string.format(globals.strCmdEmptyTrashLivePost, internalState.strTrashId) - log.dbg("Sending Empty Trash URL: " .. cmdUrl .."\n") - local body, err = browser:post_uri(cmdUrl, post) - if not body or err then - log.error_print("Error when trying to empty the trash with url: ".. cmdUrl .."\n") - end - end - - -- Empty the Junk Folder - -- - if internalState.bEmptyJunk and internalState.bLiveGUI and internalState.bLiveLightGUI == true then - cmdUrl = string.format(globals.strCmdEmptyTrashLiveLight, internalState.strMailServer, internalState.strJunkId) - local post = string.format(globals.strCmdEmptyTrashLiveLightPost, internalState.strMT) - log.dbg("Sending Empty Junk URL: " .. cmdUrl .."\n") - local body, err = browser:post_uri(cmdUrl, post) - if not body or err then - log.error_print("Error when trying to empty the junk folder with url: ".. cmdUrl .."\n") - end - elseif internalState.bEmptyJunk and internalState.bLiveGUI then - cmdUrl = string.format(globals.strCmdEmptyTrashLive, internalState.strMailServer, internalState.strUserId) - local post = string.format(globals.strCmdEmptyTrashLivePost, internalState.strJunkId) - log.dbg("Sending Empty Junk URL: " .. cmdUrl .."\n") - local body, err = browser:post_uri(cmdUrl, post) - if not body or err then - log.error_print("Error when trying to empty the junk folder with url: ".. cmdUrl .."\n") - end - end - - -- Should we force a logout. If this session runs for more than a day, things - -- stop working - -- - local currTime = os.clock() - local diff = currTime - internalState.loginTime - if diff > globals.nSessionTimeout then - if (internalState.bLiveGUI) then - cmdUrl = string.format(globals.strCmdLogoutLive, internalState.strMailServer) - else - cmdUrl = string.format(globals.strCmdLogout, internalState.strMailServer) - end - log.dbg("Sending Logout URL: " .. cmdUrl .. "\n") - local body, err = getPage(browser, cmdUrl) - - log.dbg("Logout forced to keep hotmail session fresh and tasty! Yum!\n") - log.dbg("Session removed - Account: " .. internalState.strUser .. - "@" .. internalState.strDomain .. "\n") - log.raw("Session removed (Forced by Hotmail timer) - Account: " .. internalState.strUser .. - "@" .. internalState.strDomain) - session.remove(hash()) - return POPSERVER_ERR_OK - end - - -- Save and then Free up the session - -- - session.save(hash(), serialize_state(), session.OVERWRITE) - session.unlock(hash()) - - log.dbg("Session saved - Account: " .. internalState.strUser .. - "@" .. internalState.strDomain .. "\n") - - return POPSERVER_ERR_OK -end - --- Stat command for the live gui --- -function LiveStat(pstate) - -- Local variables - -- - local browser = internalState.browser - local nMsgs = 0 - local nTotMsgs = 0; - local nMaxMsgs = 999 - if internalState.statLimit ~= nil then - nMaxMsgs = internalState.statLimit - end - - local cmdUrl = string.format(globals.strCmdMsgListLive, internalState.strMailServer, - internalState.strCrumb, internalState.strUserId) - local post = string.format(globals.strCmdMsgListPostLive, internalState.strMBox, nMaxMsgs, nMaxMsgs, internalState.strMT) - - -- Debug Message - -- - log.dbg("Stat URL: " .. cmdUrl .. "\n"); - - -- Initialize our state - -- - set_popstate_nummesg(pstate, nMsgs) - - -- Iterate over the messages - -- - local body, err = browser:post_uri(cmdUrl, post) - if (body == nil) then - -- Use the M7 way -- REMOVE THIS AT SOME POINT! - -- - post = string.format(globals.strCmdMsgListPostLiveOld, internalState.strMBox, nMaxMsgs, nMaxMsgs) - body, err = browser:post_uri(cmdUrl, post) - end - log.raw(body) - - -- Let's make sure the session is still valid - -- - local strSessExpr = string.match(body, globals.strRetLoginSessionExpiredLive) - if strSessExpr ~= nil then - -- Invalidate the session - -- - internalState.bLoginDone = nil - session.remove(hash()) - log.raw("Session Expired - Last page loaded: " .. cmdUrl .. ", Body: " .. body) - - -- Try Logging back in - -- - local status = loginHotmail() - if status ~= POPSERVER_ERR_OK then - return POPSERVER_ERR_NETWORK - end - - -- Reset the local variables - -- - browser = internalState.browser - - -- Retry to load the page - -- - body, err = browser:post_uri(cmdUrl, post) - end - - -- Go through the list of messages (M7 - DELETE SOON!) - -- - for uidl, size in string.gfind(body, globals.strMsgLivePatternOld) do - nMsgs = nMsgs + 1 - if (nMsgs <= nMaxMsgs) then - log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) - set_popstate_nummesg(pstate, nMsgs) - set_mailmessage_size(pstate, nMsgs, size) - set_mailmessage_uidl(pstate, nMsgs, uidl) - end - end - - -- Go through the list of messages (M8) - -- - local cnt = 0 - local i = 1 - local sizes = {} - for size in string.gfind(body, globals.strMsgLivePattern1) do - cnt = cnt + 1 - local kbUnit = string.match(size, "([Kk])") - size = string.match(size, "([%d%.,]+) [KkMm]") - if (size ~= nil) then - size = string.gsub(size, ",", ".") - end - if size ~= nil and tonumber(size) ~= nil then - if not kbUnit then - size = math.max(tonumber(size), 0) * 1024 * 1024 - else - size = math.max(tonumber(size), 0) * 1024 - end - else - size = 1024 - end - sizes[cnt] = size - end - - for uidl in string.gfind(body, globals.strMsgLivePattern2) do - nMsgs = nMsgs + 1 - if (nMsgs <= nMaxMsgs) then - log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. sizes[i]) - - set_popstate_nummesg(pstate, nMsgs) - set_mailmessage_size(pstate, nMsgs, sizes[i]) - set_mailmessage_uidl(pstate, nMsgs, uidl) - i = i + 1 - end - end - - -- Update our state - -- - internalState.bStatDone = true - - -- Function completed successfully - -- - return POPSERVER_ERR_OK -end - --- Stat command - Get the number of messages and their size --- -function stat(pstate) - - -- Have we done this already? If so, we've saved the results - -- - if internalState.bStatDone then - return POPSERVER_ERR_OK - end - - if internalState.bLiveGUI and internalState.bLiveLightGUI == false then - return LiveStat(pstate) - end - - -- Local variables - -- - local browser = internalState.browser - local nPage = 1 - local nMsgs = 0 - local nTotMsgs = 0 - local lastNMsgs = 0 - local cmdUrl = "" - if (internalState.bLiveLightGUI) then - cmdUrl = string.format(globals.strCmdMsgListLiveLight, internalState.strMailServer, - internalState.strMBox); - else - cmdUrl = string.format(globals.strCmdMsgList, internalState.strMailServer, - internalState.strCrumb, internalState.strMBox); - end - local baseUrl = cmdUrl - local nextPageUrl = nil - - -- Keep a list of IDs that we've seen. With yahoo, their message list can - -- show messages that we've already seen. This, although a bit hacky, will - -- keep the unique ones. We'll need to search the table on every message which - -- really sucks! - -- - local knownIDs = {} - - -- Debug Message - -- - log.dbg("Stat URL: " .. cmdUrl .. "\n"); - - -- Initialize our state - -- - set_popstate_nummesg(pstate, nMsgs) - - -- Local function to process the list of messages, getting id's and sizes - -- - local function funcProcess(body) - lastNMsgs = nMsgs - - -- Find out if there are any messages - -- - local nomesg = string.match(body, globals.strMsgListNoMsgPat) - if (nomesg ~= nil) then - return true, nil - end - - -- Tokenize out the message ID and size for each item in the list - -- - local items = mlex.match(body, globals.strMsgLineLitPattern, globals.strMsgLineAbsPattern) - log.dbg("Stat Count: " .. items:count()) - - -- Remember the count - -- - local cnt = items:count() - if cnt == 0 then - return true, nil - end - - -- Cycle through the items and store the msg id and size - -- - for i = 1, cnt do - local uidl = items:get(0, i - 1) - local size = items:get(1, i - 1) - - if not uidl or not size then - log.say("Hotmail Module needs to fix it's individual message list pattern matching.\n") - return nil, "Unable to parse the size and uidl from the html" - end - - -- Get the message id.. - -- - uidl = string.match(uidl, 'name="([^"]+)"') - - local bUnique = true - for j = 0, nMsgs do - if knownIDs[j + 1] == uidl then - bUnique = false - break - end - end - - -- Convert the size from it's string (4KB or 2MB) to bytes - -- First figure out the unit (KB or just B) - -- - local kbUnit = string.match(size, "([Kk])") - size = string.match(size, "([%d%.,]+)[KkMm]") - if (size ~= nil) then - size = string.gsub(size, ",", ".") - end - if (size ~= nil and tonumber(size) ~= nil) then - if not kbUnit then - size = math.max(tonumber(size), 0) * 1024 * 1024 - else - size = math.max(tonumber(size), 0) * 1024 - end - else - size = 1024 - end - - -- Save the information - -- - if bUnique == true and ((nMsgs < nTotMsgs and nTotMsgs ~= 0) or nTotMsgs == 0) then - nMsgs = nMsgs + 1 - log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) - set_popstate_nummesg(pstate, nMsgs) - set_mailmessage_size(pstate, nMsgs, size) - set_mailmessage_uidl(pstate, nMsgs, uidl) - knownIDs[nMsgs] = uidl - end - end - - -- We are done with this page, increment the counter - -- - nPage = nPage + 1 - - return true, nil - end - - - -- Local function to process the list of messages, getting id's and sizes - -- - local function funcProcessLiveLight(body) - lastNMsgs = nMsgs - - -- Figure out if there are more pages with messages - -- - nextPageUrl = string.match(body, globals.strMsgListNextPagePatLiveLight) - - -- Tokenize out the message ID and size for each item in the list - -- - for uidl, size in string.gfind(body, globals.strMsgLiveLightPattern) do - - if not uidl or not size then - log.say("Hotmail Module needs to fix it's individual message list pattern matching.\n") - return nil, "Unable to parse the size and uidl from the html" - end - - local bUnique = true - for j = 0, nMsgs do - if knownIDs[j + 1] == uidl then - bUnique = false - break - end - end - - -- Convert the size from it's string (4KB or 2MB) to bytes - -- First figure out the unit (KB or just B) - -- - local kbUnit = string.match(size, "([Kk])") - size = string.match(size, "([%d%.,]+)[KkMm]") - if (size ~= nil) then - size = string.gsub(size, ",", ".") - end - if (size ~= nil and tonumber(size) ~= nil) then - if not kbUnit then - size = math.max(tonumber(size), 0) * 1024 * 1024 - else - size = math.max(tonumber(size), 0) * 1024 - end - else - size = 1024 - end - - -- Save the information - -- - if bUnique == true and ((nMsgs < nTotMsgs and nTotMsgs ~= 0) or nTotMsgs == 0) then - nMsgs = nMsgs + 1 - log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) - set_popstate_nummesg(pstate, nMsgs) - set_mailmessage_size(pstate, nMsgs, size) - set_mailmessage_uidl(pstate, nMsgs, uidl) - knownIDs[nMsgs] = uidl - end - end - - -- We are done with this page, increment the counter - -- - nPage = nPage + 1 - - return true, nil - end - - -- Local Function to check for more pages of messages. If found, the - -- change the command url - -- - local function funcCheckForMorePages(body) - -- - if (internalState.bLiveLightGUI) then - if (nextPageUrl == nil) then - return true - else - cmdUrl = "http://" .. internalState.strMailServer .. "/mail/" .. nextPageUrl - return false - end - end - - -- See if there are messages remaining - -- - if nMsgs < nTotMsgs then - cmdUrl = baseUrl .. string.format(globals.strCmdMsgListNextPage, nPage) - return false - else - -- For western languages, our patterns don't work so use a backup pattern. - -- - if (lastNMsgs == nMsgs) then - return true - end - - if (nTotMsgs == 0 and - string.find(body, globals.strMsgListNextPagePattern) ~= nil) then - cmdUrl = baseUrl .. string.format(globals.strCmdMsgListNextPage, nPage) - return false - end - return true - end - end - - -- Local Function to get the list of messages - -- - local function funcGetPage() - -- Debug Message - -- - log.dbg("Debug - Getting page: ".. cmdUrl) - - -- Get the page and check to see if we got results - -- - local body, err = getPage(browser, cmdUrl) - if body == nil then - return body, err - end - - -- Check to see if we got a good page back. The folder list is - -- notorous for returning Server busy or page not available - -- - if (internalState.bLiveLightGUI == false and string.find(body, globals.strRetStatBusy) == nil) then - return nil, "Hotmail is returning an error page." - end - - -- Is the session expired - -- - local strSessExpr = string.match(body, globals.strRetLoginSessionExpired) - if strSessExpr ~= nil then - -- Invalidate the session - -- - internalState.bLoginDone = nil - session.remove(hash()) - log.raw("Session Expired - Last page loaded: " .. cmdUrl .. ", Body: " .. body) - - -- Try Logging back in - -- - local status = loginHotmail() - if status ~= POPSERVER_ERR_OK then - return nil, "Session expired. Unable to recover" - end - - -- Reset the local variables - -- - browser = internalState.browser - if (internalState.bLiveLightGUI) then - cmdUrl = string.format(globals.strCmdMsgListLiveLight, internalState.strMailServer, - internalState.strMBox); - else - cmdUrl = string.format(globals.strCmdMsgList, internalState.strMailServer, - internalState.strCrumb, internalState.strMBox); - end - baseUrl = cmdUrl - if nPage > 1 then - cmdUrl = cmdUrl .. string.format(globals.strCmdMsgListNextPage, nPage) - end - - -- Retry to load the page - -- - return getPage(browser, cmdUrl) - end - - -- Get the total number of messages - -- - if nTotMsgs == 0 then - local strTotMsgs - if (internalState.bLiveLightGUI == false) then - strTotMsgs = string.match(body, globals.strMsgListCntPattern) - else - strTotMsgs = string.match(body, globals.strMsgListLiveLightCntPattern) - end - if strTotMsgs == nil then - nTotMsgs = 0 - else - -- The number of messages can be in one of two patterns - -- - if (internalState.bLiveLightGUI == false) then - nTotMsgs = string.match(strTotMsgs, globals.strMsgListCntPattern2) - if (nTotMsgs == nil) then - nTotMsgs = 0 - end - else - nTotMsgs = strTotMsgs - end - nTotMsgs = tonumber(nTotMsgs) - end - - if internalState.statLimit ~= nil then - local nMaxMsgs = internalState.statLimit - if (nTotMsgs > nMaxMsgs) then - nTotMsgs = nMaxMsgs - end - end - - log.dbg("Total messages in message list: " .. nTotMsgs) - end - - -- Make sure the page is valid - -- - if internalState.bLiveLightGUI == false and string.find(body, globals.strMsgListGoodBody) == nil then - return nil, "Hotmail returned with an invalid page." - end - - return body, err - end - - - -- Run through the pages and pull out all the message pieces from - -- all the message lists - -- - local fnProcess = funcProcess - if (internalState.bLiveLightGUI) then - fnProcess = funcProcessLiveLight - end - if not support.do_until(funcGetPage, funcCheckForMorePages, fnProcess) then - log.error_print("STAT Failed.\n") - session.remove(hash()) - log.raw("Session removed (STAT Failure) - Account: " .. internalState.strUser .. - "@" .. internalState.strDomain) - return POPSERVER_ERR_NETWORK - end - - -- Update our state - -- - internalState.bStatDone = true - - -- Check to see that we completed successfully. If not, return a network - -- error. This is the safest way to let the email client now that there is - -- a problem but that it shouldn't drop the list of known uidls. - if (nMsgs < nTotMsgs) then - return POPSERVER_ERR_NETWORK - end - - -- Return that we succeeded - -- - return POPSERVER_ERR_OK -end - --- Fill msg uidl field --- -function uidl(pstate,msg) - return common.uidl(pstate, msg) -end - --- Fill all messages uidl field --- -function uidl_all(pstate) - return common.uidl_all(pstate) -end - --- Fill msg size --- -function list(pstate,msg) - return common.list(pstate, msg) -end - --- Fill all messages size --- -function list_all(pstate) - return common.list_all(pstate) -end - --- Unflag each message marked for deletion --- -function rset(pstate) - return common.rset(pstate) -end - --- Mark msg for deletion --- -function dele(pstate,msg) - return common.dele(pstate, msg) -end - --- Do nothing --- -function noop(pstate) - return common.noop(pstate) -end - --- Retrieve the message --- -function retr(pstate, msg, data) - downloadMsg(pstate, msg, -2, data) - return POPSERVER_ERR_OK -end - --- Top Command (like retr) --- -function top(pstate, msg, nLines, data) - downloadMsg(pstate, msg, nLines, data) - return POPSERVER_ERR_OK -end - --- Plugin Initialization - Pretty standard stuff. Copied from the manual --- -function init(pstate) - -- Let the log know that we have been found - -- - log.dbg(PLUGIN_NAME .. "(" .. PLUGIN_VERSION ..") found!\n") - - -- Import the freepops name space allowing for us to use the status messages - -- - freepops.export(pop3server) - - -- Load dependencies - -- - - -- Serialization - -- - require("serial") - - -- Browser - -- - require("browser") - - -- MIME Parser/Generator - -- - require("mimer") - - -- Common module - -- - require("common") - - -- Run a sanity check - -- - freepops.set_sanity_checks() - - -- Let the log know that we have initialized ok - -- - log.dbg(PLUGIN_NAME .. "(" .. PLUGIN_VERSION ..") initialized!\n") - - - -- Everything loaded ok - -- - return POPSERVER_ERR_OK -end - --- EOF --- ************************************************************************** -- diff --git a/mail/freepops/patches/patch-aa b/mail/freepops/patches/patch-aa index 11d34268252..428e80b1f36 100644 --- a/mail/freepops/patches/patch-aa +++ b/mail/freepops/patches/patch-aa @@ -1,9 +1,9 @@ -$NetBSD: patch-aa,v 1.2 2007/06/28 16:36:45 schmonz Exp $ +$NetBSD: patch-aa,v 1.3 2008/10/23 04:40:55 schmonz Exp $ ---- configure.sh.orig 2007-06-22 15:14:35.000000000 -0400 +--- configure.sh.orig 2008-06-11 13:33:56.000000000 -0400 +++ configure.sh -@@ -76,6 +76,13 @@ LUAFLAGS=${LUAFLAGS:-""} - LIBEXPAT_STATIC_PATH=${LIBEXPAT_STATIC_PATH:-$PWD/../lib/lib/} +@@ -75,6 +75,13 @@ LUAFLAGS=${LUAFLAGS:-""} + OSX_SDK=${OSX_SDK:-""} } +set_pkgsrc() { @@ -16,7 +16,7 @@ $NetBSD: patch-aa,v 1.2 2007/06/28 16:36:45 schmonz Exp $ set_linux() { set_default OS=Linux -@@ -304,6 +311,9 @@ case $1 in +@@ -253,6 +260,9 @@ case $1 in usage exit 1 ;; diff --git a/mail/freepops/patches/patch-ab b/mail/freepops/patches/patch-ab index a2322dc3efc..5c6fbe68f40 100644 --- a/mail/freepops/patches/patch-ab +++ b/mail/freepops/patches/patch-ab @@ -1,8 +1,8 @@ -$NetBSD: patch-ab,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ +$NetBSD: patch-ab,v 1.2 2008/10/23 04:40:55 schmonz Exp $ ---- Makefile.orig 2007-05-26 06:18:56.000000000 -0400 +--- Makefile.orig 2008-06-11 13:33:56.000000000 -0400 +++ Makefile -@@ -60,26 +60,19 @@ install: all +@@ -65,11 +65,9 @@ install: all $(H)mkdir -p $(PREFIX) $(H)mkdir -p $(PREFIX)bin $(H)mkdir -p $(PREFIX)share/freepops/lua/ @@ -16,10 +16,12 @@ $NetBSD: patch-ab,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ $(H)if [ ! -z "$(FLTKUI)" ]; then \ mkdir -p $(PREFIX)lib/freepops/; \ cp updater-ui/fltk/updater_fltk$(SHAREDEXTENSION) \ - $(PREFIX)lib/freepops/; \ - cp updater-ui/fltk/freepops-updater-fltk $(PREFIX)bin; \ +@@ -82,16 +80,10 @@ install: all + $(PREFIX)share/locale/$$lang/LC_MESSAGES/updater_fltk.mo; \ + done; \ fi - $(H)cp updater-ui/dialog/freepops-updater-dialog $(PREFIX)bin +- $(H)cp updater-ui/zenity/freepops-updater-zenity $(PREFIX)bin - $(H)chmod a+rx $(PREFIX)bin/freepops-updater-dialog $(H)cp src/freepopsd$(EXEEXTENSION) $(PREFIX)bin $(H)cp src/lua/*.lua modules/include/*.lua config.lua \ @@ -31,16 +33,16 @@ $NetBSD: patch-ab,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ $(H)mkdir -p $(PREFIX)share/freepops/lua/lxp/ $(H)mkdir -p $(PREFIX)share/freepops/lua/browser/ $(H)mkdir -p $(PREFIX)share/freepops/lua/soap/ -@@ -98,14 +91,12 @@ install: all +@@ -110,15 +102,12 @@ install: all cp $$X $(PREFIX)share/freepops/lua/soap/; \ done; \ fi - $(H)cp doc/freepopsd.1 $(PREFIX)share/man/man1/ - $(H)cp doc/freepops-updater-dialog.1 $(PREFIX)share/man/man1/ +- $(H)cp doc/freepops-updater-zenity.1 $(PREFIX)share/man/man1/ + $(H)cp doc/freepopsd.1 $(PREFIX)$(PKGMANDIR)/man1/ $(H)if [ ! -z "$(FLTKUI)" ]; then \ -- cp doc/freepops-updater-fltk.1 $(PREFIX)share/man/man1/;\ -+ cp doc/freepops-updater-fltk.1 $(PREFIX)$(PKGMANDIR)/man1/;\ + cp doc/freepops-updater-fltk.1 $(PREFIX)share/man/man1/;\ fi - $(H)cp doc/manual*.pdf $(PREFIX)share/doc/freepops/ || true $(H)cp doc/MANUAL.txt $(PREFIX)share/doc/freepops/ || true diff --git a/mail/freepops/patches/patch-ac b/mail/freepops/patches/patch-ac index a1ebfa0de3e..fc695a8d2b6 100644 --- a/mail/freepops/patches/patch-ac +++ b/mail/freepops/patches/patch-ac @@ -1,8 +1,8 @@ -$NetBSD: patch-ac,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ +$NetBSD: patch-ac,v 1.2 2008/10/23 04:40:55 schmonz Exp $ ---- doc/freepopsd.1.orig 2007-01-14 09:37:30.000000000 -0500 +--- doc/freepopsd.1.orig 2008-05-27 11:43:40.000000000 -0400 +++ doc/freepopsd.1 -@@ -54,7 +54,7 @@ a valid filename to log to this file. +@@ -51,7 +51,7 @@ a valid filename to log to this file. Moves the process to background releasing the tty .TP \fB \-n\fR, \fB\-\-no-pid-file @@ -11,11 +11,11 @@ $NetBSD: patch-ac,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ .TP \fB \-P \fRproxyaddress:proxyport, \fB\-\-proxy \fRproxyaddress:proxyport You can specify the http proxy name and port separated by :. -@@ -114,10 +114,10 @@ Prints the program version. - .\"sense only in a lan-wide installation. +@@ -144,10 +144,10 @@ Prints the program version. + .br .SH FILES .TP --.I /usr/share/frepops/lua/* +-.I /usr/share/freepops/lua/* +.I @PREFIX@/share/freepops/lua/* Webmails access implementation .TP @@ -23,4 +23,4 @@ $NetBSD: patch-ac,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ +.I @PKG_SYSCONFDIR@/config.lua Configuration file, interesting only for paths, addresses to modules binding, and accept/reject policy on mail addresses - \".TP + .SH AUTHOR diff --git a/mail/freepops/patches/patch-ad b/mail/freepops/patches/patch-ad index 92bcf533a3a..a60b9597a5a 100644 --- a/mail/freepops/patches/patch-ad +++ b/mail/freepops/patches/patch-ad @@ -1,13 +1,13 @@ -$NetBSD: patch-ad,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ +$NetBSD: patch-ad,v 1.2 2008/10/23 04:40:55 schmonz Exp $ ---- src/lua/freepops.lua.orig 2007-03-24 13:19:24.000000000 -0400 +--- src/lua/freepops.lua.orig 2007-11-12 04:47:03.000000000 -0500 +++ src/lua/freepops.lua -@@ -64,7 +64,7 @@ local __loadfile = loadfile +@@ -67,7 +67,7 @@ local __loadfile = loadfile + -- Config file loading. local function load_config() - - local paths = { -- "/etc/freepops/", -+ "@PKG_SYSCONFDIR@/", - "./", - os.getenv("FREEPOPSLUA_PATH") or "./" , - } + local conffile = os.getenv("FREEPOPSLUA_CONFFILE") +- local paths = { "/etc/freepops/", "./", os.getenv("FREEPOPSLUA_PATH") or "./" } ++ local paths = { "@PKG_SYSCONFDIR@/", "./", os.getenv("FREEPOPSLUA_PATH") or "./" } + + local try_load = + function(filename) return diff --git a/mail/freepops/patches/patch-ae b/mail/freepops/patches/patch-ae index a81fa6f8dd5..4ec42c06ad7 100644 --- a/mail/freepops/patches/patch-ae +++ b/mail/freepops/patches/patch-ae @@ -1,6 +1,6 @@ -$NetBSD: patch-ae,v 1.1.1.1 2007/06/05 05:56:01 schmonz Exp $ +$NetBSD: patch-ae,v 1.2 2008/10/23 04:40:55 schmonz Exp $ ---- src/freepops.h.orig 2007-01-14 09:37:30.000000000 -0500 +--- src/freepops.h.orig 2007-01-13 17:36:25.000000000 -0500 +++ src/freepops.h @@ -50,7 +50,7 @@ extern char *configfile; #ifdef WIN32 diff --git a/mail/freepops/patches/patch-af b/mail/freepops/patches/patch-af index d69ab710392..e995722744e 100644 --- a/mail/freepops/patches/patch-af +++ b/mail/freepops/patches/patch-af @@ -1,10 +1,10 @@ -$NetBSD: patch-af,v 1.2 2007/06/28 16:36:45 schmonz Exp $ +$NetBSD: patch-af,v 1.3 2008/10/23 04:40:55 schmonz Exp $ ---- config.h.orig 2007-06-22 07:37:59.000000000 -0400 +--- config.h.orig 2008-05-27 10:22:49.000000000 -0400 +++ config.h @@ -16,7 +16,7 @@ // common - #define VERSION "0.2.5" + #define VERSION "0.2.7" #define PROGRAMNAME "FreePOPs" -#define PIDFILE "/var/run/freepopsd.pid" +#define PIDFILE "@VARBASE@/run/freepopsd.pid" diff --git a/mail/freepops/patches/patch-ag b/mail/freepops/patches/patch-ag index 81d9886cc86..0fa7aab71d5 100644 --- a/mail/freepops/patches/patch-ag +++ b/mail/freepops/patches/patch-ag @@ -1,8 +1,8 @@ -$NetBSD: patch-ag,v 1.2 2007/06/12 22:38:52 joerg Exp $ +$NetBSD: patch-ag,v 1.3 2008/10/23 04:40:55 schmonz Exp $ ---- src/Makefile.orig 2007-04-23 17:17:37.000000000 -0400 +--- src/Makefile.orig 2008-06-04 14:33:02.000000000 -0400 +++ src/Makefile -@@ -174,7 +174,7 @@ ifeq "$(OS)" "BeOS" +@@ -169,7 +169,7 @@ ifeq "$(OS)" "BeOS" else ifeq "$(SSL)" "openssl" LDFLAGS+=-L ../modules/lib $(addprefix -l,$(LIBSTOLINK))\ diff --git a/mail/freepops/patches/patch-ah b/mail/freepops/patches/patch-ah new file mode 100644 index 00000000000..b1bde48dcd3 --- /dev/null +++ b/mail/freepops/patches/patch-ah @@ -0,0 +1,1043 @@ +$NetBSD: patch-ah,v 1.1 2008/10/23 04:40:55 schmonz Exp $ + +--- src/lua/hotmail.lua.orig 2008-05-27 10:23:22.000000000 -0400 ++++ src/lua/hotmail.lua +@@ -3,13 +3,11 @@ + -- + -- Released under the GNU/GPL license + -- Written by Russell Schwager <russell822@yahoo.com> +--- Patched by cdmackie (2007-09-11). +--- Fixed: lite login, live delete, corrupt messages, stuck at 1st message, classic delete more than 1 message + -- ************************************************************************** -- + + -- Globals + -- +-PLUGIN_VERSION = "0.1.90" ++PLUGIN_VERSION = "0.1.92" + PLUGIN_NAME = "hotmail.com" + PLUGIN_REQUIRE_VERSION = "0.2.0" + PLUGIN_LICENSE = "GNU/GPL" +@@ -21,7 +19,8 @@ PLUGIN_DOMAINS = { "@hotmail.com","@msn. + "@charter.com", "@compaq.net","@passport.com", + "@hotmail.de", "@hotmail.it", "@hotmail.co.uk", + "@hotmail.co.jp", "@hotmail.fr", "@messengeruser.com", +- "@hotmail.com.ar", "@hotmail.co.th", "@hotmail.com.tr" ++ "@hotmail.com.ar", "@hotmail.co.th", "@hotmail.com.tr", ++ "@milanosemplice.it" + } + PLUGIN_PARAMETERS = { + {name="folder", description={ +@@ -106,9 +105,9 @@ local globals = { + -- + strRetLoginBadLogin = "(memberservices)", + strRetLoginSessionExpired = "(Sign in)", +- strRetLoginSessionExpiredLiveLight = '(</li></ul><a class="ManageLink" href="ManageFoldersLight%.aspx)', ++ strRetLoginSessionExpiredLiveLight = '(href="ManageFoldersLight%.aspx)', + strRetLoginSessionErrorLive = '(HM%.FppError)', +- strRetLoginSessionExpiredLive = '(new HM%.FppReturnPackage%(0,new HM', ++ strRetLoginSessionExpiredLive = '(new HM%.FppReturnPackage%(0,new HM)', + strRetStatBusy = "(form name=.hotmail.)", + + -- Regular expression to extract the mail server +@@ -147,6 +146,8 @@ local globals = { + strRegExpCrumb = '&a=([^"&]*)[&"]', + strRegExpCrumbLive = '"sessionidhash" : "([^"]+)"', + strRegExpUser = '"authuser" : "([^"]+)"', ++ strRegExpCrumbLiveLight = 'SessionId:"([^"]+)"', ++ strRegExpUserLiveLight = 'AuthUser:"([^"]+)"', + + -- MSN Inbox Folder Id + -- +@@ -167,7 +168,7 @@ local globals = { + strFolderPattern = '<a href="[^"]+curmbox=([^&]+)&[^"]+" >', + strFolderLivePattern = '%("([^"]+)","', + strFolderLiveInboxPattern = 'sysfldrinbox".-"([^"]+)"', +- strFolderLiveLightInboxPattern = 'href="InboxLight%.aspx%?(FolderID=[^&]+[^"]+)"[^>]+><img src=".-i_inbox.gif"', ++ strFolderLiveLightInboxPattern = 'fst="NONE".-href="InboxLight%.aspx%?(FolderID=[^&]+[^"]+)"[^>]+>', + strFolderLiveLightFolderIdPattern = 'FolderID=([^&]+)&[.]*', + strFolderLiveLightNPattern = '&n=([^&]+)[.]*', + +@@ -175,7 +176,7 @@ local globals = { + strFolderLiveLightTrash2Pattern = 'href="InboxLight%.aspx%?FolderID=([^&]+)&[^"]+"[^>]+><img src="[^"]+" class="i_trash"', + strFolderLiveLightJunkPattern = 'i_junkfolder%.gif" border="0" alt=""/></td>.-<td class="dManageFoldersFolderNameCol"><a href="InboxLight%.aspx%?FolderID=([^&]+)&', + strFolderLiveLightJunk2Pattern = 'href="InboxLight%.aspx%?FolderID=([^&]+)&[^"]+"[^>]+><img src="[^"]+" class="i_junkfolder"', +- strFolderLiveLightPattern = 'href="InboxLight%.aspx%?FolderID=([^&]+&n=[^"]+)" title="', ++ strFolderLiveLightPattern = 'href="InboxLight%.aspx%?(FolderID=[^&]+[^"]+)" title="', + strFolderLiveLightManageFoldersPattern = 'href="ManageFoldersLight%.aspx%?n=([^"]+)"', + + -- Pattern to determine if we have no messages +@@ -186,19 +187,22 @@ local globals = { + -- + strMsgListCntPattern = "<td width=100. align=center>([^<]+)</td><td align=right nowrap>", + strMsgListCntPattern2 = "([%d]+) [MmNnBbVv][eai]", +- strMsgListLiveLightCntPattern = '<div class=".-ItemListHeaderMsgInfo".->.-(%d+).-</div>', +- ++ --strMsgListLiveLightCntPattern = '<div class=".-ItemListHeaderMsgInfo".->.-(%d+).-</div>', ++ strMsgListLiveLightCntPattern = '>(%d+) %a+</div><div class="PageNavigation FloatRight"', ++ + -- Used by Stat to pull out the message ID and the size + -- + strMsgLineLitPattern = ".*<tr>.*<td>[.*]{img}.*</td>.*<td>.*<img>.*</td>.*<td>[.*]{img}.*</td>.*<td>.*<input>.*</td>.*<td>.*</td>.*<td>.*<a>.*</a>.*</td>.*<td>.*</td>.*<td>.*</td>.*<td>.*</td>.*</tr>", + strMsgLineAbsPattern = "O<O>O<O>[O]{O}O<O>O<O>O<O>O<O>O<O>[O]{O}O<O>O<O>O<X>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>O<O>X<O>O<O>", + +- + -- Pattern used by Stat to get the next page in the list of messages + -- + strMsgListNextPagePattern = '(nextpg%.gif" border=0></a>)', + strMsgListNextPagePatLiveLight = '<a href="([^"]+)"[^>]*><img src="[^_]*_nextpage.gif"', + strMsgListNextPagePatLiveLight2 = '<a href="([^"]+)"[^>]*><img src="[^"]+" class="i_nextpage"', ++ strMsgListNextPagePatLiveLight3 = 'pnCur=\\?"([^\\"]+)\\?" pnAm=\\?"([^\\"]+)\\?" pnAd=\\?"([^\\"]+)\\?" pnDir=\\?"NextPage\\?" pnMid=\\?"([^\\"]+)\\?" [^>]*>.-<[^>]+>.-<img [^_]*_nextpage\\?"', ++ ++ strMsgListNextPagePatLiveLight4 = '<li id="nextPageLink" pnCur="([^"]+)" pnAm="([^"]+)" pnAd="([^"]+)" pnDir="NextPage" pnMid="([^"]+)" pnSkip="0">', + + -- Pattern used to detect a bad STAT page. + -- +@@ -209,7 +213,13 @@ local globals = { + strMsgLivePatternOld = ',"([^"]+)","[^"]+","[^"]+",[^,]+,[^,]+,[^,]+,[^,]+,"([^"]+)"', + strMsgLivePattern1 = 'class=.-SizeCell.->([^<]+)</div>', + strMsgLivePattern2 = 'new HM%.__[^%(]+%("([^"]+)",[tf][^,"]+,"[^"]+",[^,]+,[^,]+', +- strMsgLiveLightPattern = 'ReadMessageId=([^&]+)&[^>]+>.-</a></td>.-<td [^>]+>.-</td>.-<td [^>]+>([^<]+)</td>', ++ strMsgLiveLightPatternOld = 'ReadMessageId=([^&]+)&[^>]+>.-</a></td>.-<td [^>]+>.-</td>.-<td [^>]+>([^<]+)</td>', ++ -- cdmackie 2008-07-02: new message patterns for live light ++ strMsgLiveLightPattern = '(<tr[^<>]-id=\\?"[^\\"]+\\?" msg=\\?"msg\\?"[^>]->)(.-)</tr>', ++ strMsgLiveLightPatternUidl = 'id=\\?"([^\\"]+)\\?"', ++ strMsgLiveLightPatternMad = 'mad=\\?"([^\\"]+)\\?"', ++ strMsgLiveLightPatternSize = 'class=\\?"TextAlignRight\\?"[^>]->(.-)</td>', ++ strMsgLiveLightPatternUnread = "(Unread)", + + -- The amount of time that the session should time out at. + -- This is expressed in seconds +@@ -233,14 +243,24 @@ local globals = { + strCmdMsgListPostLiveOld = "cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=GetFolderData&d=%s,Date,%s,false,0,%s,0,,&MailToken=", + strCmdMsgListPostLive = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=GetFolderData&d=%s,Date,%s,false,0,%s,0,"","",true,false&v=1&mt=%s', + ++ -- cdmackie 2008-07-02: new calls for STAT for live light ++ strCmdMsgListLive3 = "mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.GetInboxData&ptid=0&a=%s&au=%s", ++ strCmdMsgListPostLive3 = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=GetInboxData&d=true,true,{%%22%s%%22,25,NextPage,0,Date,false,%%22%s%%22,%%22%s%%22,%s,%s,false,%%22%%22,false,%s},false,null&v=1&mt=%s', ++ strCmdMsgListPostLive4 = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=GetInboxData&d=true,true,{%%22%s%%22,LastPage,0,Date,false,%%22%s%%22,%%22%s%%22,%s,%s,false,%%22%%22,%s,-1,Bottom},false,null&v=1&mt=%s', ++ + strCmdDelete = "http://%s/cgi-bin/HoTMaiL", + strCmdDeletePost = "curmbox=%s&_HMaction=delete&wo=&SMMF=0", -- &<MSGID>=on + strCmdDeleteLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.MoveMessages&ptid=0&a=%s&au=%s", + strCmdDeletePostLiveOld = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MoveMessages&d="%s","%s",[%s],[{"%%5C%%7C%%5C%%7C%%5C%%7C0%%5C%%7C%%5C%%7C%%5C%%7C00000000-0000-0000-0000-000000000001%%5C%%7C632901424233870000",{2,"00000000-0000-0000-0000-000000000000",0}}],null,null,0,false,Date&v=1', + -- strCmdDeletePostLive = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MoveMessages&d="%s","%s",[%s],[{"%%5C%%7C%%5C%%7C%%5C%%7C0%%5C%%7C%%5C%%7C%%5C%%7C%%5C%%7C00000000-0000-0000-0000-000000000001%%5C%%7C632750213035330000",null}],null,null,0,false,Date,false,true&v=1&mt=%s', + strCmdDeletePostLive = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MoveMessages&d="%s","%s",[%s],[{"0%%5C%%7C0%%5C%%7C8C9BDFF65883200%%5C%%7C00000000-0000-0000-0000-000000000001",null}],null,null,0,false,Date,false,true&v=1&mt=%s', +- strCmdDeleteLiveLight = "http://%s/mail/InboxLight.aspx?FolderID=%s&", +- strCmdDeletePostLiveLight = "__VIEWSTATE=&mt=%s&MoveMessageSelector=%s&ToolbarActionItem=MoveMessageSelector&", -- SelectedMessages=%s", ++ ++ --strCmdDeleteLiveLight = "http://%s/mail/InboxLight.aspx?FolderID=%s&", ++ --strCmdDeletePostLiveLight = "__VIEWSTATE=&mt=%s&MoveMessageSelector=%s&ToolbarActionItem=MoveMessageSelector&", -- SelectedMessages=%s", ++ strCmdDeleteLiveLight = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.MoveMessagesToFolder&ptid=0&a=%s&au=%s", ++ strCmdDeletePostLiveLight = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MoveMessagesToFolder&d="%s","%s",[%s],[%s],{"%s",25,FirstPage,0,Date,false,"00000000-0000-0000-0000-000000000000","",1,2,false,"",false,0},null&v=1&mt=%s', ++ strCmdDeletePostLiveLight2 = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MoveMessagesToFolder&d="%s","%s",[%s],[%s],{"%s",FirstPage,0,Date,false,"00000000-0000-0000-0000-000000000000","",1,2,false,"",26,0,Bottom}&v=1&mt=%s', ++ + strCmdMsgView = "http://%s/cgi-bin/getmsg?msg=%s&imgsafe=y&curmbox=%s&a=%s", + strCmdMsgViewRaw = "&raw=0", + strCmdMsgViewLive = "http://%s/mail/GetMessageSource.aspx?msgid=%s&gs=true", +@@ -253,11 +273,13 @@ local globals = { + strCmdMsgUnreadLivePost = "cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MarkMessages&d=false,[%s]", + strCmdEmptyTrashLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.EmptyFolder&ptid=0&a=&au=%s", + strCmdEmptyTrashLivePost = "cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=EmptyFolder&d=%s,1&v=1&mt=%s", +- strCmdEmptyTrashLiveLight = "http://%s/mail/InboxLight.aspx?EmptyFolder=True&FolderID=%s&", +- strCmdEmptyTrashLiveLightPost = "__VIEWSTATE=&mt=%s&query=&MoveMessageSelector=&ToolbarActionItem=&InfoPaneActionItem=EmptyFolderConfirmYes", ++ strCmdEmptyTrashLiveLight = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.ClearFolder&ptid=0&a=%s&au=%s", ++ strCmdEmptyTrashLiveLightPost = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=ClearFolder&d="%s",{"%s",25,FirstPage,0,Date,false,"00000000-0000-0000-0000-000000000000","",1,2,false,"",false,0}&v=1&mt=%s', + strCmdMsgReadLive = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.MarkMessages&ptid=0&a=&au=%s", + strCmdMsgReadLivePost = "cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MarkMessages&d=true,[%s]&v=1&mt=%s", +- strCmdMsgReadLiveLight = "http://%s/mail/ReadMessageLight.aspx?AllowUnsafe=True&Aux=&FolderID=%s&InboxSortAscending=False&InboxSortBy=Date&ReadMessageId=%s", ++ --strCmdMsgReadLiveLight = "http://%s/mail/ReadMessageLight.aspx?AllowUnsafe=True&Aux=&FolderID=%s&InboxSortAscending=False&InboxSortBy=Date&ReadMessageId=%s", ++ strCmdMsgReadLiveLight = "http://%s/mail/mail.fpp?cnmn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox.MarkMessagesReadState&ptid=0&a=%s&au=%s", ++ strCmdMsgReadLiveLightPost = 'cn=Microsoft.Msn.Hotmail.Ui.Fpp.MailBox&mn=MarkMessagesReadState&d=true,["%s"],{"%s",25,FirstPage,0,Date,false,"00000000-0000-0000-0000-000000000000","",1,2,false,"",false,0}&v=1&mt=%s', + } + + -- ************************************************************************** -- +@@ -288,6 +310,8 @@ internalState = { + strUserId = "", + strMT = "", + bKeepMsgStatus = false, ++ msgIds = {}, ++ unreadStatus = {}, + } + + -- ************************************************************************** -- +@@ -354,6 +378,13 @@ end + + function getPage(browser, url, post, name) + local try = 0 ++ ++ if post ~= nil then ++ log.raw("LOADING: " .. url .. "\nPOST: " .. post .. "\n") ++ else ++ log.raw("LOADING: " .. url .. "\n") ++ end ++ + while (try < 3) do + try = try + 1 + local body, err = fetchPage(browser, url, post, name) +@@ -363,9 +394,11 @@ function getPage(browser, url, post, nam + log.error_print("Tried to load: " .. url .. " and got error: " .. err) + return nil, err + else ++ log.raw(body .. "\n\n") ++ + if (string.find(body, "We are experiencing higher than normal volume") == nil and +- string.find(body, "<[Hh][Tt][Mm][Ll]") ~= nil and +- string.find(body, "MSN Hotmail %- ERROR") == nil) then ++ (string.find(body, "<[Hh][Tt][Mm][Ll]") ~= nil or string.find(body, "new HM.FppReturnPackage") ~= nil) and ++ string.find(body, "MSN Hotmail %- ERROR") == nil ) then + return body, err + end + -- This is a little bizarre -- It seems the condition should not be here. +@@ -383,11 +416,23 @@ end + + function fetchPage(browser, url, post, name) + log.dbg("Fetching Page: " .. name .. " - " .. url) ++ local body, err + if (post == nil) then +- return browser:get_uri(url) ++ body, err = browser:get_uri(url) + else +- return browser:post_uri(url, post) ++ body, err = browser:post_uri(url, post) + end ++ ++ local lastpage = browser:whathaveweread() ++ if (string.match(lastpage, "browsersupport")) then ++ if (post == nil) then ++ body, err = browser:get_uri(url) ++ else ++ body, err = browser:post_uri(url, post) ++ end ++ end ++ ++ return body, err + end + + -- Issue the command to login to Hotmail +@@ -403,8 +448,8 @@ function loginHotmail() + + -- Create a browser to do the dirty work + -- +- --internalState.browser = browser.new("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727") +- internalState.browser = browser.new("Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12") ++ internalState.browser = browser.new("Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3") ++ --internalState.browser = browser.new("Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12") + + -- Define some local variables + -- +@@ -520,6 +565,21 @@ function loginHotmail() + body, err = getPage(browser, "http://www.hotmail.com", nil, "hotmail homepage") + end + ++ -- Let's look for a message at login ++ -- ++ local hasMsgAtLogin = false ++ url = string.match(body, '<form name="MessageAtLoginForm" method="post" action="([^"]+)"') ++ if (url ~= nil) then ++ hasMsgAtLogin = true ++ url = string.gsub(url, "&", "&") ++ local post = "" ++ for name, value in string.gfind(body, '<input type="hidden" name="([^"]+)".-value="([^"]+)"') do ++ post = post .. name .. "=" .. value .. "&" ++ end ++ url = "http://" .. browser:wherearewe() .. "/mail/" .. url ++ body, err = getPage(browser, url, post, "Message At Login Form") ++ end ++ + -- Check to see if we are using the new interface and are redirecting. + -- + local folderBody = body +@@ -560,23 +620,24 @@ function loginHotmail() + + -- Paco + body = cleanupLoginBody(body) +- +- url = string.match(body, globals.strLoginDoneReloadToHMHome1) ++ ++ url = string.match(body, globals.strLoginDoneReloadToHMHome1) + if url == nil then + url = string.match(body, globals.strLoginDoneReloadToHMHome2) + if url == nil then + -- Change suggested by 930 + local authimgurl = string.match(body, globals.strLoginDoneReloadToHMHome4) +- -- Paco +- -- +- if authimgurl == nil then +- authimgurl = string.match(body, globals.strLoginDoneReloadToHMHome5) +- end +- log.raw("Image url: " .. authimgurl) ++ ++ -- Paco ++ -- ++ if authimgurl == nil then ++ authimgurl = string.match(body, globals.strLoginDoneReloadToHMHome5) ++ end ++ log.raw("Image url: " .. authimgurl) + +- if authimgurl ~= nil then +- getPage(browser, authimgurl, nil, "Authentication Image Url - NonLive") +- end ++ if authimgurl ~= nil then ++ getPage(browser, authimgurl, nil, "Authentication Image Url - NonLive") ++ end + url = string.match(body, globals.strLoginDoneReloadToHMHome3) + if url == nil then + log.error_print(globals.strLoginFailed) +@@ -593,7 +654,7 @@ function loginHotmail() + log.error_print(globals.strLoginFailed) + log.raw("Login failed: Sent login info to: " .. (url or "none") .. " and got an error:\n" .. err); + return POPSERVER_ERR_NETWORK +- end ++ end + end + + -- Extract the crumb - This is needed for deletion of items +@@ -628,6 +689,10 @@ function loginHotmail() + -- + log.dbg("Hotmail Authuser value: " .. user .. "\n") + end ++ else ++ -- Force this to be the empty string for live light -- older versions. Eventually we could probably remove this. ++ -- ++ internalState.strCrumb = '' + end + + -- Get the MT cookie value +@@ -648,9 +713,8 @@ function loginHotmail() + + -- Find the image server + -- +- if (internalState.bLiveGUI == true) then +- str = string.match(body, globals.strImgServerLivePattern) +- else ++ str = string.match(body, globals.strImgServerLivePattern) ++ if (str == nil) then + str = string.match(body, globals.strImgServerPattern) + end + +@@ -730,16 +794,17 @@ function loginHotmail() + + body, err = getPage(browser, url, nil, "LiveLight - Manage Folders") + +- -- cdmackie: we then extract the querystring and apend the InboxId with the N value +- local inboxQueryString = string.match(body, globals.strFolderLiveLightInboxPattern) +- local inboxId = string.match(inboxQueryString, globals.strFolderLiveLightFolderIdPattern) +- local inboxN = string.match(inboxQueryString, globals.strFolderLiveLightNPattern) +- inboxId = inboxId .. "&n=" .. inboxN +- ++ -- cdmackie 2008-07-06: fix patter to get folder IDs + if (internalState.strMBoxName == "Inbox") then +- str = inboxId ++ str = string.match(body, globals.strFolderLiveLightInboxPattern) ++ local id = string.match(str, globals.strFolderLiveLightFolderIdPattern) ++ local n = string.match(str, globals.strFolderLiveLightNPattern) ++ str = id .. "&n=" .. n + else + str = string.match(body, globals.strFolderLiveLightPattern .. internalState.strMBoxName) ++ local id = string.match(str, globals.strFolderLiveLightFolderIdPattern) ++ local n = string.match(str, globals.strFolderLiveLightNPattern) ++ str = id .. "&n=" .. n + end + + if (str == nil) then +@@ -752,33 +817,49 @@ function loginHotmail() + + -- Get the trash folder id and the junk folder id + -- +- str = string.match(body, globals.strFolderLiveLightTrashPattern) +- if str ~= nil then +- internalState.strTrashId = str +- log.dbg("Hotmail - trash folder id: " .. str) +- else +- str = string.match(body, globals.strFolderLiveLightTrash2Pattern) ++ local idx = 0 ++ for folderId in string.gfind(body, "javascript:confirmDeleteFolder%('([^']+)'") do ++ if idx == 0 then ++ internalState.strJunkId = folderId ++ log.dbg("Hotmail - junk folder id: " .. folderId) ++ elseif idx == 1 then ++ internalState.strTrashId = folderId ++ log.dbg("Hotmail - trash folder id: " .. folderId) ++ end ++ idx = idx + 1 ++ end ++ ++ if (internalState.strTrashId == nil) then ++ str = string.match(body, globals.strFolderLiveLightTrashPattern) + if str ~= nil then + internalState.strTrashId = str + log.dbg("Hotmail - trash folder id: " .. str) + else +- log.error_print("Unable to detect the folder id for the trash folder. Deletion may fail.") +- end +- end ++ str = string.match(body, globals.strFolderLiveLightTrash2Pattern) ++ if str ~= nil then ++ internalState.strTrashId = str ++ log.dbg("Hotmail - trash folder id: " .. str) ++ else ++ log.error_print("Unable to detect the folder id for the trash folder. Deletion may fail.") ++ end ++ end ++ end + +- str = string.match(body, globals.strFolderLiveLightJunkPattern) +- if str ~= nil then +- internalState.strJunkId = str +- log.dbg("Hotmail - junk folder id: " .. str) +- else +- str = string.match(body, globals.strFolderLiveLightJunk2Pattern) ++ if (internalState.strJunkId == nil) then ++ str = string.match(body, globals.strFolderLiveLightJunkPattern) + if str ~= nil then + internalState.strJunkId = str + log.dbg("Hotmail - junk folder id: " .. str) + else +- log.error_print("Unable to detect the folder id for the junk folder. Deletion may fail.") +- end +- end ++ str = string.match(body, globals.strFolderLiveLightJunk2Pattern) ++ if str ~= nil then ++ internalState.strJunkId = str ++ log.dbg("Hotmail - junk folder id: " .. str) ++ else ++ log.error_print("Unable to detect the folder id for the junk folder. Deletion may fail.") ++ end ++ end ++ end + end + + -- Note that we have logged in successfully +@@ -797,7 +878,7 @@ function loginHotmail() + end + + function cleanupLoginBody(body) +- log.raw("Cleaning up login body: " .. body) ++ --log.raw("Cleaning up login body: " .. body) + body = string.gsub(body, ":", ":") + body = string.gsub(body, "=", "=") + body = string.gsub(body, "'", "'") +@@ -813,7 +894,7 @@ function cleanupLoginBody(body) + body = string.gsub(body, "\\x3f", "?") + body = string.gsub(body, "\\x3d", "=") + body = string.gsub(body, "\\x26", "&") +- log.raw("Body cleaned: " .. body) ++ --log.raw("Body cleaned: " .. body) + + return body + end +@@ -841,7 +922,6 @@ function downloadMsg(pstate, msg, nLines + -- + local browser = internalState.browser + local uidl = get_mailmessage_uidl(pstate, msg) +- + local url = string.format(globals.strCmdMsgView, internalState.strMailServer, + uidl, internalState.strMBox, internalState.strCrumb); + local markReadUrl = url +@@ -958,8 +1038,13 @@ function downloadMsg(pstate, msg, nLines + browser:post_uri(url, post) + elseif internalState.bMarkMsgAsUnread == false and internalState.bLiveGUI and internalState.bLiveLightGUI then + log.raw("Message: " .. cbInfo.cb_uidl .. ", Marking message as read.") +- url = string.format(globals.strCmdMsgReadLiveLight, internalState.strMailServer, internalState.strMBox, uidl) +- browser:get_head(url) ++ -- cdmackie: 2008-07-05 use new MarkMessagesReadState command ++ --url = string.format(globals.strCmdMsgReadLiveLight, internalState.strMailServer, internalState.strMBox, uidl) ++ url = string.format(globals.strCmdMsgReadLiveLight, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) ++ local inboxid = string.gsub(internalState.strMBox, "&n=.*", "") ++ local post = string.format(globals.strCmdMsgReadLiveLightPost, uidl, inboxid, internalState.strMT) ++ post = string.gsub(post, '"', "%%22") ++ browser:post_uri(url, post) + elseif internalState.bMarkMsgAsUnread == true and internalState.bLiveGUI == true then + log.raw("Message: " .. cbInfo.cb_uidl .. ", Marking message as unread.") + url = string.format(globals.strCmdMsgUnreadLive, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) +@@ -1059,50 +1144,57 @@ function cleanupHeaders(headers, cbInfo) + local bMissingID = false -- when no Message-ID -field seems to have been automatically generated ? + local bodyrest = "" + +- headers, bodyrest = string.match(headers, "^(.-)\r*\n%s*\r*\n(.*)$" ) ++ headers, bodyrest = string.match(headers, "^(.-\r\n.-)\r\n(.*)$" ) + + if (headers == nil) then + log.dbg("Hotmail: unable to parse out message headers. Extra headers will not be used.") + return origHeaders + end + +- headers = string.gsub(headers, "%s+$", "\n") +- headers = headers .. "\n"; +- headers = string.gsub(headers, "\n\n", "\n") +- headers = string.gsub(headers, "\r\n", "\n") +- headers = string.gsub(headers, "\n", "\r\n") ++ --headers = string.gsub(headers, "%s+$", "\n") ++ --headers = headers .. "\n"; ++ --headers = string.gsub(headers, "\n\n", "\n") ++ --headers = string.gsub(headers, "\r\n", "\n") ++ --headers = string.gsub(headers, "\n", "\r\n") + + -- + -- some checking... + -- +- if string.find(headers, "(To:)") == nil then +- bMissingTo = true +- end +- if string.find(headers, "(Message%-I[dD]:)") == nil then +- bMissingID = true +- end ++-- if string.find(headers, "(To:)") == nil then ++-- bMissingTo = true ++-- end ++-- if string.find(headers, "(Message%-I[dD]:)") == nil then ++-- bMissingID = true ++-- end + + -- Add some headers + -- ++ local newheaders = "" + if bMissingTo ~= false then +- headers = headers .. "To: " .. internalState.strUser .. "@" .. internalState.strDomain .. "\r\n" ; ++ newheaders = newheaders .. "To: " .. internalState.strUser .. "@" .. internalState.strDomain .. "\r\n" ; + end + + if bMissingID ~= false then + local msgid = cbInfo.cb_uidl .. "@" .. internalState.strMailServer -- well, if we do not have any better choice... +- headers = headers .. "Message-ID: <" .. msgid .. ">\r\n" ++ newheaders = newheaders .. "Message-ID: <" .. msgid .. ">\r\n" ++ end ++ ++ local readStatus = "read" ++ if (internalState.unreadStatus[cbInfo.cb_uidl]) then ++ readStatus = "unread" + end + +- headers = headers .. "X-FreePOPs-User: " .. internalState.strUser .. "@" .. internalState.strDomain .. "\r\n" +- headers = headers .. "X-FreePOPs-Domain: " .. internalState.strDomain .. "\r\n" +- headers = headers .. "X-FreePOPs-Folder: " .. internalState.strMBox .. "\r\n" +- headers = headers .. "X-FreePOPs-MailServer: " .. internalState.strMailServer .. "\r\n" +- headers = headers .. "X-FreePOPs-ImageServer: " .. internalState.strImgServer .. "\r\n" +- headers = headers .. "X-FreePOPs-MsgNumber: " .. "<" .. cbInfo.cb_uidl .. ">" .. "\r\n" ++ newheaders = newheaders .. "X-FreePOPs-User: " .. internalState.strUser .. "@" .. internalState.strDomain .. "\r\n" ++ newheaders = newheaders .. "X-FreePOPs-Domain: " .. internalState.strDomain .. "\r\n" ++ newheaders = newheaders .. "X-FreePOPs-Folder: " .. internalState.strMBox .. "\r\n" ++ newheaders = newheaders .. "X-FreePOPs-MailServer: " .. internalState.strMailServer .. "\r\n" ++ newheaders = newheaders .. "X-FreePOPs-ImageServer: " .. internalState.strImgServer .. "\r\n" ++ newheaders = newheaders .. "X-FreePOPs-MsgNumber: " .. "<" .. cbInfo.cb_uidl .. ">" .. "\r\n" ++ newheaders = newheaders .. "X-FREEPOPS-READ-STATUS: " .. readStatus .. "\r\n" + + -- make the final touch... + -- +- headers = headers .. "\r\n" .. bodyrest ++ headers = headers .. "\r\n" .. newheaders .. bodyrest + + return headers + end +@@ -1127,13 +1219,16 @@ function cleanupBody(body, cbInfo) + -- + body = string.gsub(body, "<pre>[%s]*", "") + body = string.gsub(body, "</pre>.-$", "\n") ++ -- cdmackie: sometimes we get only "</" ++ body = string.gsub(body, "</$", "\n") + + -- Clean up the end of line, and replace HTML tags + -- ++ body = string.gsub(body, " ", "\n") -- appears in some spam messages and destroys the headers + body = string.gsub(body, "	", "\t") + body = string.gsub(body, "	", "\t") + body = string.gsub(body, " ", "\n") +- body = string.gsub(body, " ", "\r") ++ body = string.gsub(body, " ", "") + body = string.gsub(body, "", "\27") + body = string.gsub(body, " ", " ") + body = string.gsub(body, "!", "!") +@@ -1198,9 +1293,17 @@ function cleanupBody(body, cbInfo) + body = string.gsub(body, "\r\n%.", "\r\n%.%.") + + -- Experimental -- For non-ascii users +- -- +- body = string.gsub(body, "&#(%d-);", function(c) return string.byte(c) end) +- ++ body = string.gsub(body, "&#(%d*);", ++ function(c) ++ c = tonumber(c) ++ if (c > 255) then ++ return "&#" .. c .. ";" ++ else ++ return string.char(c) ++ end ++ end ++ ) ++ + -- We've now at least seen one block, attempt to clean up the headers + -- + if (cbInfo.bFirstBlock == true) then +@@ -1397,6 +1500,7 @@ function quit_update(pstate) + local post = postBase + local uidls = "" + local uidlsLight = "" ++ local madsLight = "" + + -- Cycle through the messages and see if we need to delete any of them + -- +@@ -1420,8 +1524,15 @@ function quit_update(pstate) + post = postBase + end + elseif internalState.bLiveGUI == true and internalState.bLiveLightGUI and get_mailmessage_flag(pstate, i, MAILMESSAGE_DELETE) then +- -- cdmackie: uidlsLight should be appended for multiple messages +- uidlsLight = uidlsLight .. "SelectedMessages=" .. get_mailmessage_uidl(pstate, i) .. "&" ++ -- cdmackie: 2008-07-09 string contains UIDLS and "mad" attribute from inbox ++ local uidl, mad = string.match(internalState.msgIds[i], "(.-)&(.*)") ++ if i > 1 then ++ uidlsLight = uidlsLight .. ',"' .. uidl .. '"' ++ madsLight = madsLight .. ',{"' .. mad .. '",null}' ++ else ++ uidlsLight = '"' .. uidl .. '"' ++ madsLight = '{"' .. mad .. '",null}' ++ end + dcnt = dcnt + 1 + elseif internalState.bLiveGUI == true and get_mailmessage_flag(pstate, i, MAILMESSAGE_DELETE) then + if i > 1 then +@@ -1442,12 +1553,29 @@ function quit_update(pstate) + log.error_print("Unable to delete messages.\n") + end + elseif dcnt > 0 and internalState.bLiveGUI and internalState.bLiveLightGUI == true then +- cmdUrl = string.format(globals.strCmdDeleteLiveLight, internalState.strMailServer, internalState.strMBox) +- post = string.format(globals.strCmdDeletePostLiveLight, internalState.strMT, +- internalState.strTrashId) .. uidlsLight ++ cmdUrl = string.format(globals.strCmdDeleteLiveLight, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) ++ ++ -- This is the older interface's way to delete it. ++ -- ++ local inboxid = string.gsub(internalState.strMBox, "&n=.*", "") ++ post = string.format(globals.strCmdDeletePostLiveLight, ++ inboxid, internalState.strTrashId, ++ uidlsLight, madsLight, ++ inboxid, internalState.strMT) ++ post = string.gsub(post, '"', "%%22") + log.dbg("Sending Trash url: " .. cmdUrl .. " - " .. post) + local body, err = getPage(browser, cmdUrl, post, "Delete Messages - LiveLight") +- elseif dcnt > 0 and internalState.bLiveGUI then ++ ++ -- This is less than ideal and will need to be fixed soon. This is the newer way to delete. ++ -- ++ post = string.format(globals.strCmdDeletePostLiveLight2, ++ inboxid, internalState.strTrashId, ++ uidlsLight, madsLight, ++ inboxid, internalState.strMT) ++ post = string.gsub(post, '"', "%%22") ++ local body, err = getPage(browser, cmdUrl, post, "Delete Messages - LiveLight - Newer version") ++ ++ elseif dcnt > 0 and internalState.bLiveGUI then + cmdUrl = string.format(globals.strCmdDeleteLive, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) + uidls = string.gsub(uidls, ",", '","') + uidls = '"' .. uidls .. '"' +@@ -1476,9 +1604,11 @@ function quit_update(pstate) + log.error_print("Cannot empty trash - crumb not found\n") + end + elseif internalState.bEmptyTrash and internalState.bLiveGUI and internalState.bLiveLightGUI == true then +- cmdUrl = string.format(globals.strCmdEmptyTrashLiveLight, internalState.strMailServer, internalState.strTrashId) +- local post = string.format(globals.strCmdEmptyTrashLiveLightPost, internalState.strMT) +- log.dbg("Sending Empty Trash URL: " .. cmdUrl .."\n") ++ cmdUrl = string.format(globals.strCmdEmptyTrashLiveLight, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) ++ local inboxid = string.gsub(internalState.strMBox, "&n=.*", "") ++ local post = string.format(globals.strCmdEmptyTrashLiveLightPost,internalState.strTrashId, inboxid, internalState.strMT) ++ post = string.gsub(post, '"', "%%22") ++ log.dbg("Sending Empty Trash URL: " .. cmdUrl ..", POST: " .. post .. "\n") + local body, err = getPage(browser, cmdUrl, post, "LiveLight - Empty Trash") + if not body or err then + log.error_print("Error when trying to empty the trash with url: ".. cmdUrl .."\n") +@@ -1496,9 +1626,11 @@ function quit_update(pstate) + -- Empty the Junk Folder + -- + if internalState.bEmptyJunk and internalState.bLiveGUI and internalState.bLiveLightGUI == true then +- cmdUrl = string.format(globals.strCmdEmptyTrashLiveLight, internalState.strMailServer, internalState.strJunkId) +- local post = string.format(globals.strCmdEmptyTrashLiveLightPost, internalState.strMT) +- log.dbg("Sending Empty Junk URL: " .. cmdUrl .."\n") ++ cmdUrl = string.format(globals.strCmdEmptyTrashLiveLight, internalState.strMailServer, internalState.strCrumb, internalState.strUserId) ++ local inboxid = string.gsub(internalState.strMBox, "&n=.*", "") ++ local post = string.format(globals.strCmdEmptyTrashLiveLightPost,internalState.strJunkId, inboxid, internalState.strMT) ++ post = string.gsub(post, '"', "%%22") ++ log.dbg("Sending Empty Junk URL: " .. cmdUrl ..", POST: " .. post .. "\n") + local body, err = getPage(browser, cmdUrl, post, "LiveLight - Empty Junk") + if not body or err then + log.error_print("Error when trying to empty the junk folder with url: ".. cmdUrl .."\n") +@@ -1592,7 +1724,7 @@ function LiveStat(pstate) + post = string.format(globals.strCmdMsgListPostLiveOld, internalState.strMBox, nMaxMsgs, nMaxMsgs) + body, err = browser:post_uri(cmdUrl, post) + end +- log.raw(body) ++ --log.raw(body) + + -- Let's make sure the session is still valid + -- +@@ -1608,7 +1740,7 @@ function LiveStat(pstate) + else + strLog = strLog .. ": " .. body + end +- log.raw(strLog) ++ --log.raw(strLog) + + -- Try Logging back in + -- +@@ -1632,10 +1764,7 @@ function LiveStat(pstate) + for uidl, size in string.gfind(body, globals.strMsgLivePatternOld) do + nMsgs = nMsgs + 1 + if (nMsgs <= nMaxMsgs) then +- log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) +- set_popstate_nummesg(pstate, nMsgs) +- set_mailmessage_size(pstate, nMsgs, size) +- set_mailmessage_uidl(pstate, nMsgs, uidl) ++ processMessage(uidl, sizes[i], nMsgs, pstate) + end + end + +@@ -1666,11 +1795,7 @@ function LiveStat(pstate) + for uidl in string.gfind(body, globals.strMsgLivePattern2) do + nMsgs = nMsgs + 1 + if (nMsgs <= nMaxMsgs) then +- log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. sizes[i]) +- +- set_popstate_nummesg(pstate, nMsgs) +- set_mailmessage_size(pstate, nMsgs, sizes[i]) +- set_mailmessage_uidl(pstate, nMsgs, uidl) ++ processMessage(uidl, sizes[i], nMsgs, pstate) + i = i + 1 + end + end +@@ -1706,6 +1831,7 @@ function stat(pstate) + local nTotMsgs = 0 + local lastNMsgs = 0 + local cmdUrl = "" ++ local cmdUrlPost = nil + if (internalState.bLiveLightGUI) then + cmdUrl = string.format(globals.strCmdMsgListLiveLight, internalState.strMailServer, + internalState.strMBox); +@@ -1715,6 +1841,7 @@ function stat(pstate) + end + local baseUrl = cmdUrl + local nextPageUrl = nil ++ local nextPageUrlPost = nil + + -- Keep a list of IDs that we've seen. With yahoo, their message list can + -- show messages that we've already seen. This, although a bit hacky, will +@@ -1722,6 +1849,9 @@ function stat(pstate) + -- really sucks! + -- + local knownIDs = {} ++ ++ -- keep msgIds for Hotmail to include the n value ++ internalState.msgIds = {} + + -- Debug Message + -- +@@ -1777,33 +1907,13 @@ function stat(pstate) + break + end + end +- +- -- Convert the size from it's string (4KB or 2MB) to bytes +- -- First figure out the unit (KB or just B) +- -- +- local kbUnit = string.match(size, "([Kk])") +- size = string.match(size, "([%d%.,]+)[KkMm]") +- if (size ~= nil) then +- size = string.gsub(size, ",", ".") +- end +- if (size ~= nil and tonumber(size) ~= nil) then +- if not kbUnit then +- size = math.max(tonumber(size), 0) * 1024 * 1024 +- else +- size = math.max(tonumber(size), 0) * 1024 +- end +- else +- size = 1024 +- end ++ size = parseSize(size) + + -- Save the information + -- + if bUnique == true and ((nMsgs < nTotMsgs and nTotMsgs ~= 0) or nTotMsgs == 0) then + nMsgs = nMsgs + 1 +- log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) +- set_popstate_nummesg(pstate, nMsgs) +- set_mailmessage_size(pstate, nMsgs, size) +- set_mailmessage_uidl(pstate, nMsgs, uidl) ++ processMessage(uidl, size, nMsgs, pstate) + knownIDs[nMsgs] = uidl + end + end +@@ -1820,27 +1930,64 @@ function stat(pstate) + -- + local function funcProcessLiveLight(body) + lastNMsgs = nMsgs +- ++ + -- Figure out if there are more pages with messages + -- + nextPageUrl = string.match(body, globals.strMsgListNextPagePatLiveLight) ++ -- cdmackie 2008-07-02: qw now have to build post for subsequent page calls ++ nextPageUrlPost = nil ++ if nextPageUrl == nil then ++ local startpos, endpos, pcur, pnam, pnad, pnmid = string.find(body, globals.strMsgListNextPagePatLiveLight3) ++ local pattern4Use = false ++ if (startpos == nil) then ++ startpos, endpos, pcur, pnam, pnad, pnmid = string.find(body, globals.strMsgListNextPagePatLiveLight4) ++ pattern4Use = true ++ end ++ if startpos ~= nil then ++ nextPageUrl = string.format(globals.strCmdMsgListLive3, internalState.strCrumb, internalState.strUserId) ++ local inboxid = string.gsub(internalState.strMBox, "&n=.*", "") ++ pnad = cleanupLoginBody(pnad) -- replace : with colons ++ pnad = string.gsub(pnad, ":", "%%5C%%3A") -- replace colons with %5C%3A ++ if pattern4Use then ++ nextPageUrlPost = string.format(globals.strCmdMsgListPostLive4, inboxid, pnam, pnad, pcur, pnmid, nTotMsgs, internalState.strMT) ++ else ++ nextPageUrlPost = string.format(globals.strCmdMsgListPostLive3, inboxid, pnam, pnad, pcur, pnmid, nTotMsgs, internalState.strMT) ++ end ++ end ++ end + -- cdmackie: change in hotmail nextpage link (kept old one incase still used) + if nextPageUrl == nil then + nextPageUrl = string.match(body, globals.strMsgListNextPagePatLiveLight2) + end + if (nextPageUrl ~= nil) then +- log.dbg("Found another page of messages: " .. nextPageUrl) ++ if (nextPageUrlPost ~= nil) then ++ log.dbg("Found another page of messages: " .. nextPageUrl .. ", POST:" .. nextPageUrlPost) ++ else ++ log.dbg("Found another page of messages: " .. nextPageUrl) ++ end + end + + -- Tokenize out the message ID and size for each item in the list + -- +- for uidl, size in string.gfind(body, globals.strMsgLiveLightPattern) do ++ -- cdmackie 2008-07-02: new message patterns and different for first and ajax calls ++ for msgrow, msgcells in string.gfind(body, globals.strMsgLiveLightPattern) do ++ local mad = string.match(msgrow, globals.strMsgLiveLightPatternMad) ++ local uidl = string.match(msgrow, globals.strMsgLiveLightPatternUidl) ++ local fulluidl = uidl .. "&" .. mad ++ local size = string.match(msgcells, globals.strMsgLiveLightPatternSize) ++ if (size == nil) then ++ size = "1 KB" -- Some versions of hotmail don't display the size. ++ end + + if not uidl or not size then + log.say("Hotmail Module needs to fix it's individual message list pattern matching.\n") + return nil, "Unable to parse the size and uidl from the html" + end + ++ if (string.match(msgrow, globals.strMsgLiveLightPatternUnread)) then ++ internalState.unreadStatus[uidl] = true ++ end ++ + local bUnique = true + for j = 0, nMsgs do + if knownIDs[j + 1] == uidl then +@@ -1848,37 +1995,45 @@ function stat(pstate) + break + end + end ++ size = parseSize(size) + +- -- Convert the size from it's string (4KB or 2MB) to bytes +- -- First figure out the unit (KB or just B) ++ -- Save the information + -- +- local kbUnit = string.match(size, "([Kk])") +- size = string.match(size, "([%d%.,]+)[KkMm]") +- if (size ~= nil) then +- size = string.gsub(size, ",", ".") +- end +- if (size ~= nil and tonumber(size) ~= nil) then +- if not kbUnit then +- size = math.max(tonumber(size), 0) * 1024 * 1024 +- else +- size = math.max(tonumber(size), 0) * 1024 +- end +- else +- size = 1024 ++ if bUnique == true and ((nMsgs < nTotMsgs and nTotMsgs ~= 0) or nTotMsgs == 0) then ++ nMsgs = nMsgs + 1 ++ processMessage(uidl, size, nMsgs, pstate) ++ knownIDs[nMsgs] = uidl ++ internalState.msgIds[nMsgs] = fulluidl ++ end ++ end ++ ++ -- Some accounts haven't been upgraded to the newer version of the live light interface and thus, we need to make a second chec. ++ -- This is terrible and needs to be removed when it can be! ++ for uidl, size in string.gfind(body, globals.strMsgLiveLightPatternOld) do ++ if not uidl or not size then ++ log.say("Hotmail Module needs to fix it's individual message list pattern matching.\n") ++ return nil, "Unable to parse the size and uidl from the html" ++ end ++ ++ local bUnique = true ++ for j = 0, nMsgs do ++ if knownIDs[j + 1] == uidl then ++ bUnique = false ++ break ++ end + end ++ size = parseSize(size) + + -- Save the information + -- + if bUnique == true and ((nMsgs < nTotMsgs and nTotMsgs ~= 0) or nTotMsgs == 0) then + nMsgs = nMsgs + 1 +- log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) +- set_popstate_nummesg(pstate, nMsgs) +- set_mailmessage_size(pstate, nMsgs, size) +- set_mailmessage_uidl(pstate, nMsgs, uidl) ++ processMessage(uidl, size, nMsgs, pstate) + knownIDs[nMsgs] = uidl ++ internalState.msgIds[nMsgs] = uidl + end +- end +- ++ end ++ + -- We are done with this page, increment the counter + -- + nPage = nPage + 1 +@@ -1890,16 +2045,24 @@ function stat(pstate) + -- change the command url + -- + local function funcCheckForMorePages(body) +- -- ++ -- Prevent an infinite loop ++ -- ++ if (lastNMsgs == nMsgs) then ++ return true ++ end ++ + if (internalState.bLiveLightGUI) then + if (nextPageUrl == nil) then + return true +- else +- cmdUrl = "http://" .. internalState.strMailServer .. "/mail/" .. nextPageUrl ++ else ++ if (string.match(nextPageUrl, "^http") == nil) then ++ cmdUrl = "http://" .. internalState.strMailServer .. "/mail/" .. nextPageUrl ++ end ++ cmdUrlPost = nextPageUrlPost + return false + end + end +- ++ + -- See if there are messages remaining + -- + if nMsgs < nTotMsgs then +@@ -1908,10 +2071,6 @@ function stat(pstate) + else + -- For western languages, our patterns don't work so use a backup pattern. + -- +- if (lastNMsgs == nMsgs) then +- return true +- end +- + if (nTotMsgs == 0 and + string.find(body, globals.strMsgListNextPagePattern) ~= nil) then + cmdUrl = baseUrl .. string.format(globals.strCmdMsgListNextPage, nPage) +@@ -1930,7 +2089,7 @@ function stat(pstate) + + -- Get the page and check to see if we got results + -- +- local body, err = getPage(browser, cmdUrl, nil, "STAT Page - LiveLight and NonLive") ++ local body, err = getPage(browser, cmdUrl, cmdUrlPost, "STAT Page - LiveLight and NonLive") + if body == nil then + return body, err + end +@@ -1944,9 +2103,21 @@ function stat(pstate) + + -- Is the session expired + -- +- local strSessExpr = string.match(body, globals.strRetLoginSessionExpired) +- local strSessExprLight = string.match(body, globals.strRetLoginSessionExpiredLiveLight) +- if strSessExpr ~= nil or strSessExprLight == nil then ++ -- dhh 2008-07-05: fix for non live light interface. ++ local bSessionExpired = false ++ if (internalState.bLiveLightGUI == false) then ++ local strSessExpr = string.match(body, globals.strRetLoginSessionExpired) ++ if strSessExpr ~= nil then ++ bSessionExpired = true ++ end ++ else ++ local strSessExprLight = string.match(body, globals.strRetLoginSessionExpiredLiveLight) ++ local strSessExprLive = string.match(body, globals.strRetLoginSessionExpiredLive) ++ if strSessExprLight == nil and strSessExprLive == nil then ++ bSessionExpired = true ++ end ++ end ++ if bSessionExpired == true then + -- Invalidate the session + -- + internalState.bLoginDone = nil +@@ -1981,6 +2152,16 @@ function stat(pstate) + return getPage(browser, cmdUrl, nil, "STAT Page - LiveLight and NonLive") + end + ++ -- cdmackie 2008-07-02: live light needs crumb now ++ if (internalState.bLiveLightGUI) then ++ if internalState.strCrumb == "" then ++ internalState.strCrumb = string.match(body, globals.strRegExpCrumbLiveLight) ++ end ++ if internalState.strUserId == "" then ++ internalState.strUserId = string.match(body, globals.strRegExpUserLiveLight) ++ end ++ end ++ + -- Get the total number of messages + -- + if nTotMsgs == 0 then +@@ -2048,8 +2229,14 @@ function stat(pstate) + -- Check to see that we completed successfully. If not, return a network + -- error. This is the safest way to let the email client now that there is + -- a problem but that it shouldn't drop the list of known uidls. +- if (nMsgs < nTotMsgs) then +- return POPSERVER_ERR_NETWORK ++ if (nMsgs < nTotMsgs and nMsgs > 0) then ++ log.error_print("The plugin needs updating. Expecting to find: " .. nTotMsgs .. ++ " and processed " .. nMsgs) ++ return POPSERVER_ERR_OK ++ elseif (nMsgs < nTotMsgs and nMsgs == 0) then ++ log.error_print("The plugin needs updating. Expecting to find: " .. nTotMsgs .. ++ " but wasn't able to process any.") ++ return POPSERVER_ERR_NETWORK + end + + -- Return that we succeeded +@@ -2057,6 +2244,34 @@ function stat(pstate) + return POPSERVER_ERR_OK + end + ++function processMessage(uidl, size, nMsgs, pstate) ++ log.dbg("Processed STAT - Msg: " .. nMsgs .. ", UIDL: " .. uidl .. ", Size: " .. size) ++ set_popstate_nummesg(pstate, nMsgs) ++ set_mailmessage_size(pstate, nMsgs, size) ++ set_mailmessage_uidl(pstate, nMsgs, uidl) ++end ++ ++function parseSize(size) ++ -- Convert the size from it's string (4KB or 2MB) to bytes ++ -- First figure out the unit (KB or just B) ++ -- ++ local kbUnit = string.match(size, "([Kk])") ++ size = string.match(size, "([%d%.,]+)%s*[KkMm]") -- cdmackie 2008-07-02: fix for space ++ if (size ~= nil) then ++ size = string.gsub(size, ",", ".") ++ end ++ if (size ~= nil and tonumber(size) ~= nil) then ++ if not kbUnit then ++ size = math.max(tonumber(size), 0) * 1024 * 1024 ++ else ++ size = math.max(tonumber(size), 0) * 1024 ++ end ++ else ++ size = 1024 ++ end ++ return size ++end ++ + -- Fill msg uidl field + -- + function uidl(pstate,msg) diff --git a/mail/freepops/patches/patch-ai b/mail/freepops/patches/patch-ai new file mode 100644 index 00000000000..f8c165b5be0 --- /dev/null +++ b/mail/freepops/patches/patch-ai @@ -0,0 +1,526 @@ +$NetBSD: patch-ai,v 1.1 2008/10/23 04:40:55 schmonz Exp $ + +--- src/lua/yahoo.lua.orig 2008-10-23 00:05:23.000000000 -0400 ++++ src/lua/yahoo.lua +@@ -14,7 +14,7 @@ + local _DEBUG = false + local DBG_LEN = nil -- 500 + +-PLUGIN_VERSION = "0.2.1" ++PLUGIN_VERSION = "0.2.1g" + PLUGIN_NAME = "yahoo.com" + PLUGIN_REQUIRE_VERSION = "0.2.0" + PLUGIN_LICENSE = "GNU/GPL" +@@ -27,6 +27,7 @@ PLUGIN_AUTHORS_CONTACTS = + PLUGIN_DOMAINS = {"@yahoo.com", "@yahoo.ie", "@yahoo.it", "@yahoo.ca", "@rocketmail.com", "@yahoo.com.ar", + "@yahoo.co.in", "@yahoo.co.id", "@yahoo.com.tw", "@yahoo.co.uk", "@yahoo.com.cn", + "@yahoo.es", "@yahoo.de", "@talk21.com", "@btinternet.com", "@yahoo.com.au", "@yahoo.co.nz", ++ "@ymail.com", "@yahoo.in" + } + + PLUGIN_PARAMETERS = { +@@ -87,6 +88,18 @@ pulling messages. Set the value to 1.]] + Parameter is used to force the plugin to only download a maximum number of messages. ]] + } + }, ++ {name = "keepmsgstatus", description = { ++ en = [[ ++Parameter is used to maintain the status of the message in the state it was before being pulling. If the value is 1, the behavior is turned on ++and will override the markunread flag. ]] ++ } ++ }, ++ {name = "domain", description = { ++ en = [[ ++Parameter is used to override the domain in the email address. This is used so that users don't ++need to add a mapping to config.lua for a hosted hotmail account. ]] ++ } ++ }, + } + + PLUGIN_DESCRIPTIONS = { +@@ -155,20 +168,28 @@ local globals = { + -- Pattern to determine if we have no messages. If this is found, we have messages. + -- + strMsgListNoMsgPat = "(<tbody>)", ++ ++ -- Pattern to determine if we have no messages with 'mc'. If found, there is no messages. ++ -- ++ strMsgListNoMsgPatMC = '(modulecontainer filled nomessages)', + + -- Used by Stat to pull out the message ID and the size + -- + strMsgLineLitPattern = ".*<td>[.*]{div}[.*]{h2}.*<a>.*</a>[.*]{/h2}[.*]{/div}.*</td>.*<td>.*</td>.*<td>.*</td>.*</tr>", + strMsgLineAbsPattern = "O<O>[O]{O}[O]{O}O<X>O<O>[O]{O}[O]{O}O<O>O<O>O<O>O<O>X<O>O<O>", +- ++ ++ strMCUnreadPattern = '<tr class="([^"]+)"><td><b>[^<]+</b></td><td[^>]+><input type="checkbox" name="mid" value="([^"]+)"', ++ + -- MSGID Pattern + -- +- strMsgIDPattern = 'MsgId=([^&]*)&', +- strMsgIDMCPattern = 'mid=([^&]*)&', ++ strMsgIDPattern = 'MsgId=([^&"]*)[&"]', ++ strMsgIDMCPattern = 'mid=([^&"]*)[&"]', ++ strMsgIDMIPattern = 'DMid=([^&"]*)[&"]', + + -- Pattern used by Stat to get the next page in the list of messages + -- + strMsgListPrevPagePattern = '<a href="/([my][cm][^"]*previous=1[^"]*)">', ++ strMsgListNextPagePatternMC = '| <a href="([^"]+)"><span[^|]+| <a href="[^"]+&last=1">', + + -- Pattern for emptying all + -- +@@ -192,8 +213,8 @@ local globals = { + + -- Command URLS + -- +- strCmdMsgList = "%s%s/ShowFolder?box=%s&Npos=%d&Nview=%s&view=%s&order=down&sort=date&reset=1&Norder=up", +- strCmdMsgListMC = "%s%s/showFolder?fid=%s&startMid=%s&ymv=0&&sort=date&order=down&filterBySelect=%s&filterBySelect=%s&prefNumOfMid=500", ++ strCmdMsgList = "%s%s/ShowFolder?box=%s&Npos=%d&filterBySelect=%s&order=down&sort=date&reset=1&Norder=up&filterButton=Go", ++ strCmdMsgListMC = "%s%s/showFolder?fid=%s&startMid=%s&ymv=0&&sort=date&order=down&filterBySelect=%s&prefNumOfMid=500&filterButton=Go", + strCmdMsgView = "%sya/download?box=%s&MsgId=%s&bodyPart=%s&download=1&YY=38663&y5beta=yes&y5beta=yes&order=down&sort=date&pos=0&view=a&head=b&DataName=&tnef=&Idx=0", + strCmdMsgWebView = "%s%s/ShowLetter?box=%s&MsgId=%s", + strCmdMsgWebViewMC = "%s%s/showMessage?fid=%s&midIndex=0&mid=%s&eps=&f=1&", +@@ -207,9 +228,9 @@ local globals = { + + -- Emails to list - These define the filter on the messages to grab + -- +- strViewAll = "a", +- strViewUnread = "u", +- strViewFlagged = "f", ++ strViewAll = "all", ++ strViewUnread = "unread", ++ strViewFlagged = "flagged", + + strViewAllPat = "([Aa]ll)", + strViewUnreadPat = "([Uu]nread)", +@@ -298,9 +319,11 @@ internalState = { + bEmptyTrash = false, + bEmptyBulk = false, + msgids = {}, ++ unreadMsgs = {}, + strStatCache = nil, + statLimit = nil, + classicType = nil, ++ bKeepMsgStatus = false, + + -- New Interface pieces + -- +@@ -350,7 +373,7 @@ function table_to_string(t, depth) + ) + result = "{" .. table.concat(tmp,", ") .. "}" + else +- result = tostring(val) ++ result = tostring(t) + end + return result + end +@@ -584,7 +607,8 @@ function loginYahoo() + + -- Create a browser to do the dirty work (It must be set to IE 6.0) + -- +- internalState.browser = browser.new("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {02ABE9F9-C33D-95EA-0C84-0B70CD0AC3F8}; .NET CLR 1.1.4322)") ++ internalState.browser = browser.new("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en) AppleWebKit/525.9 (KHTML, like Gecko) Version/3.1 Safari/525.9") ++ --browser.new("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {02ABE9F9-C33D-95EA-0C84-0B70CD0AC3F8}; .NET CLR 1.1.4322)") + -- internalState.browser = browser.new("Mozilla/4.0 (compatible; U; en)") + -- internalState.browser = browser.new("Mozilla/3.0 (U; en)") + -- internalState.browser = browser.new("FreePOPs/2.5 (U; en)") +@@ -601,15 +625,10 @@ function loginYahoo() + local post + local challengeCode, uVal + +- -- Handle rocketmail ++ -- Add the domain always + -- +- if (domain == "rocketmail.com") then +- domain = "yahoo.com" +- username = username .. ".rm" +- elseif (domain == "btinternet.com" or domain == "talk21.com") then +- username = username .. "@" .. domain +- end +- ++ username = username .. "@" .. domain ++ + -- DEBUG - Set the browser in verbose mode + -- + -- browser:verbose_mode() +@@ -661,10 +680,31 @@ function loginYahoo() + log.dbg( "login redirect response: err=" .. tostr(err), dbg_limit(body) ) + end + ++ -- Check for interstitial page (advertisements) ++ -- ++ url = browser:whathaveweread() ++ log.dbg("browser:whathaveweread()=" .. url) ++ str = string.match( url, '(http://.-interstitial.-/)[^/]*' ) ++ if (str ~= nil) then ++ local str2 = string.match(body, '<a id="skip" href="([^"]+")>') ++ if (str2 ~= nil) then ++ str2 = string.gsub(str2, "./", "") ++ log.dbg("Found the link to get by interstitutial ad.") ++ url = str .. str2 ++ else ++ log.dbg("Did not find the link to get by interstitutial ad. Try one that worked at some point.") ++ log.dbg("Page Body: " .. body) ++ url = str .. "mail_act.php?mpref=2" -- from skip() in http://us.i1.yimg.com/us.yimg.com/lib/tb7/mail_interstitial/mail_20080612.js ++ end ++ log.dbg( "interstitial get: url=" .. url ) ++ body, err = browser:get_uri(url) ++ log.dbg( "interstitial response: err=" .. tostr(err), dbg_limit(body) ) ++ url = browser:whathaveweread() ++ log.dbg("browser:whathaveweread()=" .. url) ++ end ++ + -- Check for NewGUI and Try Beta + local bNewGui = false +- local url = browser:whathaveweread() +- log.dbg("browser:whathaveweread()=" .. url) + str = string.match(url, '/dc/try_mail') + if (str == nil) then + -- it's not a "try" page. Check if its the new gui. +@@ -964,9 +1004,8 @@ function downloadYahooMsg(pstate, msg, n + -- Get the header + -- + if internalState.bNewGUI then +- local msgid = internalState.msgids[uidl] +- uidl = msgid +- headers = getMsgHdr(pstate, uidl) ++ msgid = internalState.msgids[uidl] ++ headers = getMsgHdr(pstate, msgid) + elseif (internalState.classicType == 'mc') then + msgid = internalState.msgids[uidl] + hdrUrl = string.format(globals.strCmdAttach, internalState.strFileServer, +@@ -1038,6 +1077,22 @@ function downloadYahooMsg(pstate, msg, n + if string.sub(headers,1,5) == "From " then + headers = string.gsub(headers, "From .-\n", "", 1); + end ++ ++ -- Add custom headers ++ -- ++ local readStatus = "read" ++ if (internalState.unreadMsgs[uidl] == 1) then ++ readStatus = "unread" ++ end ++ local crlf ++ if (internalState.bNewGUI) then ++ crlf = "\n" ++ headers = string.gsub(headers, "\n+$", "") ++ else ++ crlf = "\r\n" ++ headers = string.gsub(headers, "\r\n\r\n$", "") ++ end ++ headers = headers .. crlf .. "X-FREEPOPS-READ-STATUS: " .. readStatus .. crlf .. crlf + + -- Remove "Content-Transfer-Encoding" line from the header. + -- +@@ -1063,7 +1118,7 @@ function downloadYahooMsg(pstate, msg, n + if nLines == 0 then + cbInfo.strText = "" + else +- getMsgBody(pstate, uidl, size, cbInfo) ++ getMsgBody(pstate, msgid, size, cbInfo) + end + mimer.pipe_msg( + headers, +@@ -1215,7 +1270,9 @@ function downloadYahooMsg(pstate, msg, n + + -- Do we need to mark the message as unread? + -- +- if internalState.bNewGUI and internalState.bMarkMsgAsUnread == true then ++ if (internalState.bKeepMsgStatus == true) then ++ -- no op ++ elseif internalState.bNewGUI and internalState.bMarkMsgAsUnread == true then + log.dbg("Marking as message: " .. uidl .. " as unread"); + markMsgUnread(uidl) + elseif internalState.bNewGUI == false and internalState.classicType ~= 'mc' then +@@ -1420,7 +1477,7 @@ function getSTATList(pstate) + local browser = internalState.browser + local url = string.format(globals.strSoapCmd, internalState.strMailServer, + internalState.strWebSrvUrl, "ListMessages", internalState.strCrumb) +- local nMaxMsgs = 999 ++ local nMaxMsgs = 9999 + if internalState.statLimit ~= nil then + nMaxMsgs = internalState.statLimit + end +@@ -1451,7 +1508,7 @@ function getSTATList(pstate) + + -- Parse the message id's and sizes + -- +- if (ipairs == nil) then ++ if (ent == nil) then + internalState.bStatDone = true + return POPSERVER_ERR_OK + end +@@ -1472,6 +1529,16 @@ function getSTATList(pstate) + break + end + end ++ ++ local flagElem = elem[1] ++ if (flagElem["tag"] == "flags") then ++ attrs = flagElem["attr"] ++ local readAttr = attrs["isRead"] ++ if (readAttr == "0") then ++ log.dbg("Message: " .. uidl .. " is unread.") ++ internalState.unreadMsgs[uidl] = 1 ++ end ++ end + + -- Save the information + -- +@@ -1525,6 +1592,8 @@ function getMsgHdr(pstate, uidl) + end + + function getMsgBody(pstate, uidl, size, cbInfo) ++ log.dbg("YahooNew getMsgBody - Entering") ++ + local browser = internalState.browser + local url = string.format(globals.strSoapCmd, internalState.strMailServer, + internalState.strWebSrvUrl, "GetMessage", internalState.strCrumb) +@@ -1540,50 +1609,70 @@ function getMsgBody(pstate, uidl, size, + + -- Get the parts + -- +- local part = nil +- local major = nil ++ ++-- log.dbg("YahooNew getMsgBody ent[3]=",tostr(ent[3])) ++ + for i, elem in ipairs (ent[3]) do + if (type(elem) == "table" and elem["tag"] == "part") then +- part = elem + local attrs = elem["attr"] + local partId = attrs["partId"] + local type = attrs["type"] + local subtype = attrs["subtype"] ++ local textElem = elem[1] ++ ++ local idPlain = nil ++ local idHtml = nil ++ + -- log.dbg("YahooNew getMsgBody partId="..tostr(partId).. + -- ", type="..tostr(type)..", subtype="..tostr(subtype).. ++-- ", textElem="..tostr(textElem).. + -- ", attrs=",tostr(attrs)) +- -- partId=1 is usually the main text (1.1) and html (1.2), +- -- which is handled above and therefore not included in attachments. +- -- don't assume any other plain or html is the main text +- if (subtype == "plain") then +- local textElem = elem[1] ++ ++ -- The main body plain-text and html are handled by the first ++ -- two tests and should not be included in attachments. ++ -- multipart/alternative results in two parts: text (1), html (2) ++ -- if there are more parts (e.g. attachments), the multi/alt body ++ -- is usually within the first part, so: text (1.1) and html (1.2) ++ -- Don't assume any other plain or html is part of the main body ++ ++ if (cbInfo.strText == nil) and ++ textElem and textElem["tag"] == "text" and ++ (subtype == "plain" or ++ (type == "text" and subtype == "")) then ++ idPlain = partId ++ log.dbg("YahooNew getMsgBody: adding plain text body = "..tostr(idPlain)) + local text = textElem[1] + if (text == nil) then + text = "" + end + text = text .. "\n" + cbInfo.strText = getMsgCallBack(cbInfo, text) +- -- remove major part from attachments +- major = string.match(partId,"(.-)%.") +- major = major or partId +- cbInfo.attachments[major] = nil +- elseif (subtype == "html") then +- local textElem = elem[1] ++ -- remove part from attachments ++ cbInfo.attachments[idPlain] = nil ++ ++ elseif (cbInfo.strHtml == nil) and ++ textElem and textElem["tag"] == "text" and ++ subtype == "html" then ++ idHtml = partId ++ log.dbg("YahooNew getMsgBody: adding html body = "..tostr(idHtml)) + local text = textElem[1] + text = string.gsub(text, "&", "&") + -- text = string.gsub(text, "(</[^>]+>) ", "%1\r\n") + text = text .. "\n" + cbInfo.strHtml = getMsgCallBack(cbInfo, text) +- -- remove major part from attachments +- major = string.match(partId,"(.-)%.") +- major = major or partId +- cbInfo.attachments[major] = nil ++ -- remove part from attachments ++ cbInfo.attachments[idHtml] = nil ++ + elseif (partId == "HEADER" or partId == "TEXT") then ++ log.dbg("YahooNew getMsgBody: partId ignored: "..tostr(partId)) + -- no-op ++ + else + -- Only add to attachments once, by partId +- -- We want only whole parts, not subparts (so no ".") +- if (string.match(partId,"%.") == nil) then ++ -- We only want the leaves, not the multipart groupings ++ if (type ~= "multipart") and ++ (partId ~= idPlain) and (partId ~= idHtml) then ++ log.dbg("YahooNew getMsgBody: adding an attachment = "..tostr(partId)) + local file = attrs["dispParams"] + local contentId = attrs["contentId"] + if (file ~= nil) then +@@ -1592,15 +1681,13 @@ function getMsgBody(pstate, uidl, size, + url = string.format(globals.strCmdAttach, internalState.strMailServer, + internalState.strMBox, escUidl, partId, internalState.strMailServer) + cbInfo.attachments[partId] = getRealAttachmentUrl(url) +- -- cbInfo.attachments[file] = getRealAttachmentUrl(url) +- -- table.insert(cbInfo.attachments, cbInfo.attachments[file]) + -- an empty contentId is not a valid contentId + if ((contentId ~= nil) and (contentId ~= "")) then + contentId = string.sub(contentId, 2, -2) + cbInfo.inlineids[partId] = contentId +- -- cbInfo.inlineids[file] = contentId +- -- table.insert(cbInfo.inlineids, table.getn(cbInfo.inlineids) + 1, contentId) + end ++ else ++ log.dbg("YahooNew getMsgBody: nil dispParams -- attachment NOT ADDED.") + end + end + end +@@ -1723,7 +1810,16 @@ function user(pstate, username) + local domain = freepops.get_domain(username) + local user = freepops.get_name(username) + +- internalState.strDomain = domain ++ -- Override the domain variable if it is set in the login parameter ++ -- ++ local val = (freepops.MODULE_ARGS or {}).domain or nil ++ if val ~= nil then ++ log.dbg("Yahoo: Using overridden domain: " .. val) ++ internalState.strDomain = val ++ else ++ internalState.strDomain = domain ++ end ++ + internalState.strUser = user + + -- Figure out the domain specific flags +@@ -1850,6 +1946,15 @@ function user(pstate, username) + internalState.statLimit = tonumber(val) + end + ++ -- If the flag keepmsgstatus=1 is set, then we won't touch the status of ++ -- messages that we pull. ++ -- ++ local val = (freepops.MODULE_ARGS or {}).keepmsgstatus or 0 ++ if val == "1" then ++ log.dbg("Yahoo: All messages pulled will have its status left alone.") ++ internalState.bKeepMsgStatus = true ++ end ++ + return POPSERVER_ERR_OK + end + +@@ -2093,8 +2198,7 @@ function stat(pstate) + local nPage = 0 + local nMsgs = 0 + local cmdUrl = string.format(strCmd, internalState.strMailServer, +- internalState.classicType, internalState.strMBox, nPage, internalState.strView, +- internalState.strView); ++ internalState.classicType, internalState.strMBox, nPage, internalState.strView); + + -- Keep a list of IDs that we've seen. With yahoo, their message list can + -- show messages that we've already seen. This, although a bit hacky, will +@@ -2121,16 +2225,18 @@ function stat(pstate) + -- Find out if there are any messages + -- + local nomesg = string.match(body, globals.strMsgListNoMsgPat) +- if (nomesg == nil) then ++ local nomesgMC = string.match(body, globals.strMsgListNoMsgPatMC) ++ if (nomesg == nil and internalState.classicType ~= "mc") then + return true, nil ++ elseif (nomesgMC ~= nil and internalState.classicType == "mc") then ++ return true, nil + end + + -- Find only the HTML containing the message list + -- + local subBody = string.match(body, globals.strMsgListHTMLPattern) + if (subBody == nil) then +- log.say("Yahoo Module needs to fix it's message list pattern matching.") +- return false, nil ++ return true, nil + end + + -- Tokenize out the message ID and size for each item in the list +@@ -2163,7 +2269,8 @@ function stat(pstate) + -- Get the message id. It's a series of a numbers followed by + -- an underscore repeated. + -- +- msgid = string.match(msgid, globals.strMsgIDPattern) or string.match(msgid, globals.strMsgIDMCPattern) ++ msgid = string.match(msgid, globals.strMsgIDPattern) or ++ string.match(msgid, globals.strMsgIDMCPattern) or string.match(msgid, globals.strMsgIDMIPattern) + local uidl = string.gsub(msgid, "_[^_]-_[^_]-_", "_000_000_", 1); + uidl = string.sub(uidl, 1, 60) + +@@ -2179,11 +2286,17 @@ function stat(pstate) + -- First figure out the unit (KB or just B) + -- + local kbUnit = string.match(size, "([Kk])") +- size = string.match(size, "([%d]+)[KkbB]") +- if not kbUnit then +- size = math.max(tonumber(size), 0) +- else ++ local mbUnit = string.match(size, "([Mm])") ++ size = string.match(size, "([%d]+)[ ]-[KkMmbB]") ++ if size == nil then ++ size = 1024 ++ end ++ if kbUnit then + size = math.max(tonumber(size), 0) * 1024 ++ elseif mbUnit then ++ size = math.max(tonumber(size), 0) * 1024 * 1024 ++ else ++ size = math.max(tonumber(size), 0) + end + + -- Save the information +@@ -2198,6 +2311,17 @@ function stat(pstate) + internalState.msgids[uidl] = msgid + end + end ++ ++ log.dbg("Looking for unread messages.") ++ for clazz, uidl in string.gfind(body, globals.strMCUnreadPattern) do ++ uidl = string.gsub(uidl, "/", "%%2F") ++ uidl = string.gsub(uidl, "_[^_]-_[^_]-_", "_000_000_", 1); ++ uidl = string.sub(uidl, 1, 60) ++ if (clazz == "msgnew") then ++ log.dbg("Message: " .. uidl .. " is unread.") ++ internalState.unreadMsgs[uidl] = 1 ++ end ++ end + + return true, nil + end +@@ -2206,7 +2330,7 @@ function stat(pstate) + -- change the command url + -- + local function funcCheckForMorePages(body) +- if internalState.statLimit ~= nil and internalState.statLimit >= nMsgs then ++ if internalState.statLimit ~= nil and internalState.statLimit <= nMsgs then + return true + end + +@@ -2218,6 +2342,12 @@ function stat(pstate) + cmdUrl = internalState.strMailServer .. nextURL + return false + else ++ nextURL = string.match(body, globals.strMsgListNextPagePatternMC) ++ if (nextURL ~= nil) then ++ cmdUrl = internalState.strMailServer .. internalState.classicType .. "/" .. nextURL ++ return false ++ end ++ + return true + end + end |