From c86a24ab61ae44afb7c2a134f59bef15046fe7bf Mon Sep 17 00:00:00 2001 From: Ted Trask Date: Fri, 29 Aug 2008 20:58:22 +0000 Subject: Added etrn support to fetchmail. Needs to be tested. git-svn-id: svn://svn.alpinelinux.org/acf/fetchmail/trunk@1439 ab2d0c66-481e-0410-8bed-d214d4d58bed --- fetchmail-model.lua | 285 ++++++++++++++++++++++++++-------------------------- 1 file changed, 143 insertions(+), 142 deletions(-) diff --git a/fetchmail-model.lua b/fetchmail-model.lua index 8c3fd84..3f39ae8 100644 --- a/fetchmail-model.lua +++ b/fetchmail-model.lua @@ -14,7 +14,7 @@ local configfile = "/etc/fetchmailrc" local confdfile = "/etc/conf.d/fetchmail" local config -local methods = {"pop3","imap","pop3domain", } +local methods = {"pop3","imap","pop3domain", "etrn", } -- ################################################################################ -- LOCAL FUNCTIONS @@ -66,133 +66,123 @@ local function writeentryline(entrystruct, entryline) -- If there is a structure, create the entryline array if entrystruct then entryline = entryline or {} - if entrystruct.value.enabled.value then - entryline[1] = "poll" - else - entryline[1] = "skip" - end - entryline[2] = entrystruct.value.remotehost.value + insertentries = {} local reverseentry = {} for i,word in ipairs(entryline) do reverseentry[word] = i end - -- server options must come before user options, so add user option to end - -- and add server options just after remotehost (3) - -- start with the user options so we can add to the end and not mess up reverseentry - -- this means that we do method last - if reverseentry["user"] or reverseentry["username"] then - entryline[(reverseentry["user"] or reverseentry["username"])+1] = entrystruct.value.remotemailbox.value - else - entryline[#entryline+1] = "username" - entryline[#entryline+1] = entrystruct.value.remotemailbox.value - end - if reverseentry["pass"] or reverseentry["password"] then - entryline[(reverseentry["pass"] or reverseentry["password"])+1] = '"'..entrystruct.value.remotepassword.value..'"' - else - entryline[#entryline+1] = "password" - entryline[#entryline+1] = '"'..entrystruct.value.remotepassword.value..'"' - end - if reverseentry["smtphost"] then - entryline[reverseentry["smtphost"]+1] = entrystruct.value.localhost.value - else - entryline[#entryline+1] = "smtphost" - entryline[#entryline+1] = entrystruct.value.localhost.value - end - -- add in some user options - if not reverseentry["rewrite"] then - entryline[#entryline+1] = "no" - entryline[#entryline+1] = "rewrite" - end - if not reverseentry["fetchall"] then - entryline[#entryline+1] = "fetchall" - end - -- now handle the method, localmailbox, and localdomain - if entrystruct.value.method.value == "pop3domain" then - if reverseentry["to"] then - entryline[reverseentry["to"]+1] = "*" + -- Server options must come before user options, so add user option to end + -- and add server options just after remotehost (3). To do this, we'll use an array + -- of insertentries that will be inserted at the end. To delete entries, just set + -- them to nil, creating a sparse array. We can fix that at the end also + -- Here are two helper functions + function setserveroption(option, value) + if reverseentry[option] then + entryline[reverseentry[option]+1] = value else - entryline[#entryline+1] = "to" - entryline[#entryline+1] = "*" + insertentries[table.maxn(insertentries)+1] = option + insertentries[table.maxn(insertentries)+1] = value end - if reverseentry["smtpaddress"] then - entryline[reverseentry["smtpaddress"]+1] = entrystruct.value.localdomain.value + end + function setuseroption(option, value) + if reverseentry[option] then + entryline[reverseentry[option]+1] = value else - entryline[#entryline+1] = "smtpaddress" - entryline[#entryline+1] = entrystruct.value.localdomain.value - end - if reverseentry["is"] then - -- THIS MESSES UP reverseentry FOR THE USER OPTIONS - table.remove(entryline, reverseentry["is"]) - table.remove(entryline, reverseentry["is"]) + entryline[table.maxn(entryline)+1] = option + entryline[table.maxn(entryline)+1] = value end - if reverseentry["proto"] or reverseentry["protocol"] then - entryline[(reverseentry["proto"] or reverseentry["protocol"])+1] = "pop3" - else - -- THIS MESSES UP reverseentry FOR EVERYTHING - table.insert(entryline, 3, "pop3") - table.insert(entryline, 3, "protocol") - -- FIX reverseentry - reverseentry = {} - for i,word in ipairs(entryline) do reverseentry[word] = i end + end + function deleteoption(option) + if reverseentry[option] then + entryline[reverseentry[option]] = nil end - if reverseentry["local"] or reverseentry["localdomains"] then - entryline[(reverseentry["local"] or reverseentry["localdomains"])+1] = entrystruct.value.localdomain.value - else - -- THIS MESSES UP reverseentry FOR EVERYTHING - table.insert(entryline, 3, entrystruct.value.localdomain.value) - table.insert(entryline, 3, "localdomains") + end + function deleteoptionandvalue(option) + if reverseentry[option] then + entryline[reverseentry[option]] = nil + entryline[reverseentry[option]+1] = nil end - if not reverseentry["dns"] then - -- THIS MESSES UP reverseentry FOR EVERYTHING - table.insert(entryline, 3, "dns") - table.insert(entryline, 3, "no") + end + function deletenooption(option) + if reverseentry[option] then + entryline[reverseentry[option]] = nil + local test = entryline[reverseentry[option]-1] + if test and test == "no" then + entryline[reverseentry[option]-1] = nil + end end + end + + -- Now we can start to set stuff + if entrystruct.value.enabled.value then + entryline[1] = "poll" else - if reverseentry["is"] then - entryline[reverseentry["is"]+1] = entrystruct.value.localmailbox.value - else - entryline[#entryline+1] = "is" - entryline[#entryline+1] = entrystruct.value.localmailbox.value - end - if reverseentry["to"] then - -- THIS MESSES UP reverseentry FOR THE USER OPTIONS - table.remove(entryline, reverseentry["to"]) - table.remove(entryline, reverseentry["to"]) - -- FIX reverseentry - reverseentry = {} - for i,word in ipairs(entryline) do reverseentry[word] = i end - end - if reverseentry["smtpaddress"] then - -- THIS MESSES UP reverseentry FOR THE USER OPTIONS - table.remove(entryline, reverseentry["smtpaddress"]) - table.remove(entryline, reverseentry["smtpaddress"]) + entryline[1] = "skip" + end + entryline[2] = entrystruct.value.remotehost.value + -- generic stuff + deleteoptionandvalue("proto") + deleteoptionandvalue("local") + deleteoptionandvalue("user") + deleteoptionandvalue("pass") + -- remove here and there + for i=1,table.maxn(entryline) do + if entryline[i] == "here" or entryline[i] == "there" then + entryline[i] = nil end - if reverseentry["proto"] or reverseentry["protocol"] then - entryline[(reverseentry["proto"] or reverseentry["protocol"])+1] = entrystruct.value.method.value - else - -- THIS MESSES UP reverseentry FOR EVERYTHING - table.insert(entryline, 3, entrystruct.value.method.value) - table.insert(entryline, 3, "protocol") - -- FIX reverseentry - reverseentry = {} - for i,word in ipairs(entryline) do reverseentry[word] = i end + end + if entrystruct.value.method.value == "pop3domain" then + setserveroption("protocol", "pop3") + setserveroption("localdomains", entrystruct.value.localdomain.value) + deleteoptionandvalue("is") + setuseroption("to", "*") + setuseroption("smtpaddress", entrystruct.value.localdomain.value) + deleteoptionandvalue("fetchdomains") + elseif entrystruct.value.method.value == "etrn" then + setserveroption("protocol", entrystruct.value.method.value) + deleteoptionandvalue("localdomains") + deleteoptionandvalue("is") + deleteoptionandvalue("to") + deleteoptionandvalue("smtpaddress") + setuseroption("fetchdomains", entrystruct.value.localdomain.value) + else -- Method not pop3domain or etrn + setserveroption("protocol", entrystruct.value.method.value) + deleteoptionandvalue("localdomains") + setuseroption("is", entrystruct.value.localmailbox.value) + deleteoptionandvalue("to") + deleteoptionandvalue("smtpaddress") + deleteoptionandvalue("fetchdomains") + end + if entrystruct.value.method.value == "etrn" then + deletenooption("dns") + deleteoptionandvalue("username") + deleteoptionandvalue("password") + deleteoptionandvalue("smtphost") + deletenooption("rewrite") + deleteoption("fetchall") + else -- Method not etrn + if not reverseentry["dns"] then + insertentries[table.maxn(insertentries)+1] = "no" + insertentries[table.maxn(insertentries)+1] = "dns" end - if reverseentry["local"] or reverseentry["localdomains"] then - -- THIS MESSES UP reverseentry FOR EVERYTHING - table.remove(entryline, (reverseentry["local"] or reverseentry["localdomains"])) - table.remove(entryline, (reverseentry["local"] or reverseentry["localdomains"])) + setuseroption("username", entrystruct.value.remotemailbox.value) + setuseroption("password", '"'..entrystruct.value.remotepassword.value..'"') + setuseroption("smtphost", entrystruct.value.localhost.value) + if not reverseentry["rewrite"] then + entryline[table.maxn(entryline)+1] = "no" + entryline[table.maxn(entryline)+1] = "rewrite" end - if not reverseentry["dns"] then - -- THIS MESSES UP reverseentry FOR EVERYTHING - table.insert(entryline, 3, "dns") - table.insert(entryline, 3, "no") + if not reverseentry["fetchall"] then + entryline[table.maxn(entryline)+1] = "fetchall" end end - -- remove here and there - for i=#entryline,1,-1 do - if entryline[i] == "here" or entryline[i] == "there" then - table.remove(entryline, i) - end + -- Now, insert the insertentries and remove the nil entries + table.insert(insertentries, 1, entryline[1]) + table.insert(insertentries, 2, entryline[2]) + for i=3,table.maxn(entryline) do + table.insert(insertentries, entryline[i]) end + insertentries.linenum = entryline.linenum + entryline = insertentries end local file = fs.read_file(configfile) @@ -216,56 +206,64 @@ local function writeentryline(entrystruct, entryline) end local function validateentry(entry) + function cannotbeblank(value) + if value.value == "" then + value.errtxt = "Invalid entry - cannot be blank" + success = false + end + end + function mustbeblank(value) + if value.value ~= "" then + value.errtxt = "Invalid entry - must be blank for this method" + success = false + end + end + local success = true success = modelfunctions.validateselect(entry.value.method) and success - if entry.value.remotehost.value == "" then - entry.value.remotehost.errtxt = "Invalid entry - cannot be blank" - success = false - elseif string.find(entry.value.remotehost.value, "[^%w.-]") then + if string.find(entry.value.remotehost.value, "[^%w.-]") then entry.value.remotehost.errtxt = "Invalid entry - may only contain alphanumeric, '.', or '-'" success = false end - if entry.value.remotemailbox.value == "" then - entry.value.remotemailbox.errtxt = "Invalid entry - cannot be blank" - success = false - elseif string.find(entry.value.remotemailbox.value, "[^%w.-_@]") then + if string.find(entry.value.remotemailbox.value, "[^%w.-_@]") then entry.value.remotemailbox.errtxt = "Invalid entry" success = false end - if entry.value.remotepassword.value == "" then - entry.value.remotepassword.errtxt = "Invalid entry - cannot be blank" - success = false - elseif string.find(entry.value.remotepassword.value, "%s") then + if string.find(entry.value.remotepassword.value, "%s") then entry.value.remotepassword.errtxt = "Invalid entry - cannot contain whitespace" success = false end - if entry.value.localhost.value == "" then - entry.value.localhost.errtxt = "Invalid entry - cannot be blank" - success = false - elseif string.find(entry.value.localhost.value, "[^%w.-]") then + if string.find(entry.value.localhost.value, "[^%w.-]") then entry.value.localhost.errtxt = "Invalid entry - may only contain alphanumeric, '.', or '-'" success = false end - if entry.value.method.value == "pop3domain" and entry.value.localmailbox.value ~= "" then - entry.value.localmailbox.errtxt = "Cannot define local mailbox for pop3domain method" - success = false - elseif entry.value.method.value ~= "pop3domain" and entry.value.localmailbox.value == "" then - entry.value.localmailbox.errtxt = "Invalid entry - cannot be blank" - success = false - elseif string.find(entry.value.localmailbox.value, "[^%w.-_@]") then + if string.find(entry.value.localmailbox.value, "[^%w.-_@]") then entry.value.localmailbox.errtxt = "Invalid entry" success = false end - if entry.value.method.value ~= "pop3domain" and entry.value.localdomain.value ~= "" then - entry.value.localdomain.errtxt = "Cannot define local domain unless pop3domain method" - success = false - elseif entry.value.method.value == "pop3domain" and entry.value.localdomain.value == "" then - entry.value.localdomain.errtxt = "Invalid entry - cannot be blank" - success = false - elseif string.find(entry.value.localdomain.value, "[^%w.-]") then + if string.find(entry.value.localdomain.value, "[^%w.-]") then entry.value.localdomain.errtxt = "Invalid entry - may only contain alphanumeric, '.', or '-'" success = false end + cannotbeblank(entry.value.remotehost) + if entry.value.method.value == "etrn" then + mustbeblank(entry.value.remotemailbox) + mustbeblank(entry.value.remotepassword) + mustbeblank(entry.value.localhost) + mustbeblank(entry.value.localmailbox) + cannotbeblank(entry.value.localdomain) + else + cannotbeblank(entry.value.remotemailbox) + cannotbeblank(entry.value.remotepassword) + cannotbeblank(entry.value.localhost) + if entry.value.method.value == "pop3domain" then + mustbeblank(entry.value.localmailbox) + cannotbeblank(entry.value.localdomain) + else + cannotbeblank(entry.value.localmailbox) + mustbeblank(entry.value.localdomain) + end + end return success, entry end @@ -314,7 +312,7 @@ end function update_filecontent(filedetails) filedetails.value.filename.value = configfile -- FIXME - validation - local retvel = modelfunctions.setfiledetails(filedetails) + local retval = modelfunctions.setfiledetails(filedetails) posix.chmod(configfile, "rwx--x---") config = nil return retval @@ -436,6 +434,9 @@ function readentry(entryname) if reverseentry["is"] then localmailbox.value = entry[reverseentry["is"]+1] or localmailbox.value end + if reverseentry["fetchdomains"] then + localdomain.value = entry[reverseentry["fetchdomains"]+1] or localdomain.value + end end return cfe({ type="group", value={enabled=enabled, method=method, remotehost=remotehost, remotemailbox=remotemailbox, remotepassword=remotepassword, localhost=localhost, localmailbox=localmailbox, localdomain=localdomain}, label="Fetchmail Entry" }) -- cgit v1.2.3