summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mail/freepops/Makefile8
-rw-r--r--mail/freepops/PLIST10
-rw-r--r--mail/freepops/distinfo24
-rw-r--r--mail/freepops/files/hotmail.lua2002
-rw-r--r--mail/freepops/patches/patch-aa10
-rw-r--r--mail/freepops/patches/patch-ab18
-rw-r--r--mail/freepops/patches/patch-ac14
-rw-r--r--mail/freepops/patches/patch-ad20
-rw-r--r--mail/freepops/patches/patch-ae4
-rw-r--r--mail/freepops/patches/patch-af6
-rw-r--r--mail/freepops/patches/patch-ag6
-rw-r--r--mail/freepops/patches/patch-ah1043
-rw-r--r--mail/freepops/patches/patch-ai526
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 &egrave; 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 &egrave; 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&igrave; che il plugin segni come non letti i messaggi che scarica. Se il valore &egrave; 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, "&#9;", "\t")
- body = string.gsub(body, "&#09;", "\t")
- body = string.gsub(body, "&#10;", "\n")
- body = string.gsub(body, "&#13;", "\r")
- body = string.gsub(body, "&#32;", " ")
- body = string.gsub(body, "&#33;", "!")
- body = string.gsub(body, "&#35;", "#")
- body = string.gsub(body, "&#36;", "$")
- -- cdmackie: this should be escaped
- body = string.gsub(body, "&#37;", "%%")
- body = string.gsub(body, "&#38;", "&")
- body = string.gsub(body, "&#39;", "'")
- body = string.gsub(body, "&#40;", "(")
- body = string.gsub(body, "&#41;", ")")
- body = string.gsub(body, "&#42;", "*")
- body = string.gsub(body, "&#43;", "+")
- body = string.gsub(body, "&#44;", ",")
- body = string.gsub(body, "&#45;", "-")
- body = string.gsub(body, "&#46;", ".")
- body = string.gsub(body, "&#47;", "/")
- body = string.gsub(body, "&#58;", ":")
- body = string.gsub(body, "&#59;", ";")
- body = string.gsub(body, "&#60;", "<")
-
- -- cdmackie: these mess up QP and b64 encoded attachments
- --body = string.gsub(body, "&#61;2E", ".")
- --body = string.gsub(body, "&#61;3D", "=")
- --body = string.gsub(body, "&#61;20", " ")
- --body = string.gsub(body, "&#61;09", "\t")
- --body = string.gsub(body, "&#61;96", "-")
- --body = string.gsub(body, "&#61;\r\n", "")
- --body = string.gsub(body, "&#61;92", "'")
-
- body = string.gsub(body, "&#61;", "=")
- body = string.gsub(body, "&#62;", ">")
- body = string.gsub(body, "&#63;", "?")
- body = string.gsub(body, "&#64;", "@")
- body = string.gsub(body, "&#91;", "[")
- body = string.gsub(body, "&#92;", "\\")
- body = string.gsub(body, "&#93;", "]")
- body = string.gsub(body, "&#94;", "^")
- body = string.gsub(body, "&#95;", "_")
- body = string.gsub(body, "&#96;", "`")
- body = string.gsub(body, "&#123;", "{")
- body = string.gsub(body, "&#124;", "|")
- body = string.gsub(body, "&#125;", "}")
- body = string.gsub(body, "&#126;", "~")
-
- body = string.gsub(body, "\r", "")
- body = string.gsub(body, "\n", "\r\n")
- -- cdmackie: these mess up QP attachments
- --body = string.gsub(body, "&amp;", "&")
- --body = string.gsub(body, "&lt;", "<")
- --body = string.gsub(body, "&gt;", ">")
- --body = string.gsub(body, "&quot;", "\"")
- body = string.gsub(body, "&#34;", "\"")
- --body = string.gsub(body, "&nbsp;", " ")
- 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, "&amp;", "&")
++ 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, "&#58;", ":")
+ body = string.gsub(body, "&#61;", "=")
+ body = string.gsub(body, "&#39;", "'")
+@@ -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, "&#13;&#10; &#13;&#10;", "\n") -- appears in some spam messages and destroys the headers
+ body = string.gsub(body, "&#9;", "\t")
+ body = string.gsub(body, "&#09;", "\t")
+ body = string.gsub(body, "&#10;", "\n")
+- body = string.gsub(body, "&#13;", "\r")
++ body = string.gsub(body, "&#13;", "")
+ body = string.gsub(body, "&#27;", "\27")
+ body = string.gsub(body, "&#32;", " ")
+ body = string.gsub(body, "&#33;", "!")
+@@ -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 &#58; 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, "&amp;", "&")
+ -- 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