diff --git a/address/expand.go b/address/expand.go index 16d2eaa..103126b 100644 --- a/address/expand.go +++ b/address/expand.go @@ -38,8 +38,6 @@ func ExpandAlias(email string) string { if rfc5322.IsQuotedAddress(email) == true { return "" } // Do not expand "neko+cat"@example.org // neko+straycat@example.org => neko@example.org - lpart := email[0:strings.Index(email, "+")] - dpart := strings.SplitN(email, "@", 2)[1] - return lpart + "@" + dpart + return email[0:strings.Index(email, "+")] + "@" + strings.SplitN(email, "@", 2)[1] } diff --git a/address/find.go b/address/find.go index 4a13d37..4f60f37 100644 --- a/address/find.go +++ b/address/find.go @@ -216,8 +216,7 @@ func Find(argv1 string) [3]string { // Try to use the string like an email address in the display name for _, e := range strings.Split(readbuffer[1], " ") { // Find an email address - if rfc5322.IsEmailAddress(e) == false { continue } - readbuffer[0] = e; break + if rfc5322.IsEmailAddress(e) { readbuffer[0] = e; break } } } else if IsMailerDaemon(readbuffer[1]) == true { // Allow if the string is MAILER-DAEMON @@ -230,10 +229,7 @@ func Find(argv1 string) [3]string { // - (cat)nekochan@example.org // - nekochan(cat)cat@example.org // - nekochan(cat)@example.org - p1 := strings.Index(readbuffer[0], "(") - p2 := strings.Index(readbuffer[0], ")") - ce := readbuffer[0][p1:p2 + 1] - + ce := "(" + sisimoji.Select(readbuffer[0], "(", ")", 0) + ")" readbuffer[0] = strings.Replace(readbuffer[0], ce, "", 1) if len(readbuffer[2]) == 0 { readbuffer[2] = ce } else { readbuffer[2] += " " + ce } } diff --git a/address/lib.go b/address/lib.go index 3e5c5cf..9ff7132 100644 --- a/address/lib.go +++ b/address/lib.go @@ -60,7 +60,7 @@ func IsIncluded(argv0 string) bool { // Such as "nekochan (kijitora) neko@example.jp" for _, e := range strings.Split(argv0, " ") { // Is there any email address string in each element? - e = strings.Trim(e, "<>"); if rfc5322.IsEmailAddress(e) { return true } + if rfc5322.IsEmailAddress(strings.Trim(e, "<>")) { return true } } } return false @@ -71,7 +71,6 @@ func IsMailerDaemon(email string) bool { // @param string email Email address // @return bool true: is a mailer-daemon // false: is not a mailer-daemon - match := false value := strings.ToLower(email) table := []string{ "mailer-daemon@", "(mailer-daemon)", "", "mailer-daemon ", @@ -80,5 +79,5 @@ func IsMailerDaemon(email string) bool { for _, e := range table { if strings.Contains(value, e) || value == "mailer-daemon" || value == "postmaster" { return true } } - return match + return false } diff --git a/address/rise.go b/address/rise.go index adaa80c..c3a017e 100644 --- a/address/rise.go +++ b/address/rise.go @@ -10,7 +10,7 @@ package address import "strings" import "libsisimai.org/sisimai/sis" -// Rise() is a constructor of Sisimai::Address +// Rise() is a constructor of sis.EmailAddress func Rise(argvs [3]string) sis.EmailAddress { // @param [3]string argvs ["Email address", "name", "comment"] // @return sis.EmailAddress EmailAddress struct when the email address was not valid diff --git a/arf/lib.go b/arf/lib.go index 4ad1130..9d2deec 100644 --- a/arf/lib.go +++ b/arf/lib.go @@ -182,8 +182,7 @@ func Inquire(bf *sis.BeforeFact) sis.RisingUnderway { } else if strings.HasPrefix(e, "Reporting-MTA: ") { // The header is optional and MUST NOT appear more than once. // Reporting-MTA: dns; mx.example.jp - cv := rfc1894.Field(e); if len(cv) == 0 { continue } - reportedby = cv[2] + if cv := rfc1894.Field(e); len(cv) > 0 { reportedby = cv[2] } } else if strings.HasPrefix(e, "Source-IP: ") { // The header is optional and MUST NOT appear more than once. @@ -216,9 +215,7 @@ func Inquire(bf *sis.BeforeFact) sis.RisingUnderway { } else { // Pick it from the original message part - p1 := strings.Index(emailparts[1], "\nTo:"); if p1 < 0 { break } - p2 := sisimoji.IndexOnTheWay(emailparts[1], "\n", p1 + 4); if p2 < 0 { break } - cv := sisiaddr.S3S4(emailparts[1][p1 + 4:p2]) + cv := sisiaddr.S3S4(sisimoji.Select(emailparts[1], "\nTo:", "\n", 0)) // There is no valid email address in the To: header of the original message such as // To: diff --git a/fact/rise.go b/fact/rise.go index 6cf0e29..684c455 100644 --- a/fact/rise.go +++ b/fact/rise.go @@ -103,8 +103,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s } for _, v := range datevalues { // Parse each date string using net/mail.ParseDate() - times, nyaan := mail.ParseDate(v); if nyaan != nil { continue } - clock = times; break + if times, nyaan := mail.ParseDate(v); nyaan == nil { clock = times; break } } if clock.IsZero() { // Failed to parse the date string at the previous loop, @@ -113,8 +112,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s // Try to parse the date string tidied by rfc5322.Date() j := rfc5322.Date(v); if j != "" { // rfc5322.Date() returned a valid date string - times, nyaan := mail.ParseDate(j); if nyaan != nil { continue } - clock = times; break + if times, nyaan := mail.ParseDate(j); nyaan == nil { clock = times; break } } } } @@ -146,8 +144,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s for li := 0; li < le; li++ { // Check the Received: headers forwards and get a local hostnaame cv := rfc5322.Received((*beforefact).Headers["received"][li]) - if rfc1123.IsInternetHost(cv[0]) == false { continue } - e.Lhost = cv[0]; break + if rfc1123.IsInternetHost(cv[0]) { e.Lhost = cv[0]; break } } } @@ -167,8 +164,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s for _, w := range ee { // Get a hostname from the string like "127.0.0.1 x109-20.example.com 192.0.2.20" // or "mx.sp.example.jp 192.0.2.135" - if rfc791.IsIPv4Address(w) { continue } - *v = w; break + if rfc791.IsIPv4Address(w) == false { *v = w; break } } if strings.Index(*v, " ") > 0 { *v = ee[0] } } @@ -191,10 +187,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s // Get the value of List-Id header: "List name " if len(rfc822data["list-id"]) == 0 { break LIST_ID } if sisimoji.Aligned(rfc822data["list-id"][0], []string{"<", ".", ">"}) == false { break LIST_ID } - p0 := strings.Index(rfc822data["list-id"][0], "<"); if p0 < 0 { break LIST_ID } - p1 := strings.Index(rfc822data["list-id"][0], ">"); if p1 < 0 { break LIST_ID } - - piece["listid"] = rfc822data["list-id"][0][p0 + 1:p1]; break LIST_ID + piece["listid"] = sisimoji.Select(rfc822data["list-id"][0], "<", ">", 0); break LIST_ID } DIAGNOSTICCODE: for { @@ -319,7 +312,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s hops := len(recv) for i := hops - 1; hops >= 0; hops-- { // Search for the string " for " from the Received: header - if strings.Index(recv[i], " for ") == -1 { continue } + if strings.Index(recv[i], " for ") == -1 { continue } or := rfc5322.Received(recv[i]) if len(or) == 0 || or[5] == "" { continue } @@ -335,7 +328,7 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s REASON: for thing.Reason == "" || RetryIndex[thing.Reason] { // Decide the reason of the email bounce // The value of thing.Reason is empty or is needed to check with other values again - re := thing.Reason; if re == "" { re = "undefined" } + re := thing.Reason; if re == "" { re = "undefined" } or := lda.Find(&thing); if reason.IsExplicit(or) { thing.Reason = or; break REASON } or = rhost.Find(&thing); if reason.IsExplicit(or) { thing.Reason = or; break REASON } or = reason.Find(&thing); if reason.IsExplicit(or) { thing.Reason = or; break REASON } @@ -352,9 +345,8 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s } else { // The Reason is not "delivered", or "feedback", or "vacation" - smtperrors := piece["deliverystatus"] + " " + piece["diagnosticcode"] - if len(smtperrors) < 4 { smtperrors = "" } - thing.HardBounce = failure.IsHardBounce(thing.Reason, smtperrors) + cv := piece["deliverystatus"] + " " + piece["diagnosticcode"]; if len(cv) < 4 { cv = "" } + thing.HardBounce = failure.IsHardBounce(thing.Reason, cv) } break HARDBOUNCE } @@ -363,10 +355,9 @@ func Rise(email *string, origin string, args *sis.DecodingArgs) ([]sis.Fact, []s // Set a pseudo status code if thing.DeliveryStatus != "" { break DELIVERYSTATUS } - smtperrors := thing.ReplyCode + " " + piece["diagnosticcode"] - if len(smtperrors) < 4 { smtperrors = "" } - permanent0 := failure.IsPermanent(smtperrors) - temporary0 := failure.IsTemporary(smtperrors) + ce := thing.ReplyCode + " " + piece["diagnosticcode"]; if len(ce) < 4 { ce = "" } + permanent0 := failure.IsPermanent(ce) + temporary0 := failure.IsTemporary(ce) temporary1 := temporary0; if !permanent0 && !temporary0 { temporary1 = false } thing.DeliveryStatus = status.Code(thing.Reason, temporary1) break DELIVERYSTATUS diff --git a/lhost/order.go b/lhost/order.go index 74a6c79..8aa5be4 100644 --- a/lhost/order.go +++ b/lhost/order.go @@ -51,9 +51,7 @@ func OrderBySubject(title string) []string { } // The following order is decided by the first 2 words of Subject: header - title = strings.Replace(title, "[", " ", -1) - title = strings.Replace(title, "]", " ", -1) - title = strings.Replace(title, "_", " ", -1) + for _, e := range []string{"[", "]", "_"} { title = strings.Replace(title, e, " ", -1) } // Squeeze duplicated space characters for strings.Contains(title, " ") { title = strings.ReplaceAll(title, " ", " ") } @@ -70,11 +68,7 @@ func OrderBySubject(title string) []string { // Postmaster notify, returned mail, ... first = strings.Join(words[0:2], "-") } - - first = strings.ReplaceAll(first, `:`, "") - first = strings.ReplaceAll(first, `,`, "") - first = strings.ReplaceAll(first, `*`, "") - first = strings.ReplaceAll(first, `"`, "") + for _, e := range []string{`:`, `,`, `*`, `"`} { first = strings.ReplaceAll(first, e, "") } return table[first] } diff --git a/lhost/via-activehunter.go b/lhost/via-activehunter.go index 4c3beab..b15a7e2 100644 --- a/lhost/via-activehunter.go +++ b/lhost/via-activehunter.go @@ -40,8 +40,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if e == "" { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // ----- The following addresses had permanent fatal errors ----- // @@ -63,9 +62,8 @@ func init() { // ----- Transcript of session follows ----- // 550 sorry, no mailbox here by that name (#5.1.1 - chkusr) cr := []rune(e[0:1]) - if cr[0] < 48 || cr[0] > 122 { continue } // 48 = '0', 122 = 'z' - if v.Diagnosis != "" { continue } - v.Diagnosis = e + if cr[0] < 48 || cr[0] > 122 { continue } // 48 = '0', 122 = 'z' + if v.Diagnosis == "" { v.Diagnosis = e } } } if recipients == 0 { return sis.RisingUnderway{} } diff --git a/lhost/via-amazonses.go b/lhost/via-amazonses.go index 0d86876..4e480c3 100644 --- a/lhost/via-amazonses.go +++ b/lhost/via-amazonses.go @@ -46,9 +46,7 @@ func init() { // "TopicArn" : "arn:aws:sns:us-west-2:123456789012:SES-EJ-B", // "Message" : "{\"notificationType\"... if strings.Contains(sespayload, "\\") { sespayload = strings.ReplaceAll(sespayload, "\\", "") } - p3 := sisimoji.IndexOnTheWay(sespayload, "{", p2 + 9) - p4 := sisimoji.IndexOnTheWay(sespayload, "\n", p2 + 9) - sespayload = sespayload[p3:p4] + sespayload = "{" + sisimoji.Select(sespayload, "{", "\n", p2 + 9) sespayload = strings.TrimRight(sespayload, ",") sespayload = strings.TrimRight(sespayload, `"`) } @@ -288,8 +286,7 @@ func init() { for f := range reasonpair { // Try to find the bounce reason by "bounceSubType" - if reasonpair[f] != (*o).BounceSubType { continue } - v.Reason = f; break + if reasonpair[f] == (*o).BounceSubType { v.Reason = f; break } } } } else if whatnotify == "C" { diff --git a/lhost/via-apachejames.go b/lhost/via-apachejames.go index e50360d..a53a8c2 100644 --- a/lhost/via-apachejames.go +++ b/lhost/via-apachejames.go @@ -29,7 +29,7 @@ func init() { for _, e := range bf.Headers["received"] { // Received: from localhost ([127.0.0.1]) // by mx.example.org (JAMES SMTP Server 2.3.2) with SMTP ID 220... - if strings.Contains(e, "JAMES SMTP Server") == true { proceedsto = true; break ISJAMES } + if strings.Contains(e, "JAMES SMTP Server") == true { proceedsto = true; break ISJAMES } } break } @@ -64,8 +64,7 @@ func init() { if e != "" { v.Diagnosis += e + " " } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Message details: // Subject: Nyaaan diff --git a/lhost/via-biglobe.go b/lhost/via-biglobe.go index f30ce47..6a8ee89 100644 --- a/lhost/via-biglobe.go +++ b/lhost/via-biglobe.go @@ -54,8 +54,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // This is a MIME-encapsulated message. // @@ -85,8 +84,7 @@ func init() { } else { // The boundary string or the error messages - if strings.Contains(e, "--") { continue } - v.Diagnosis += e + " " + if strings.Contains(e, "--") == false { v.Diagnosis += e + " " } } } if recipients == 0 { return sis.RisingUnderway{} } @@ -100,13 +98,12 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } - } + } } diff --git a/lhost/via-courier.go b/lhost/via-courier.go index fbb5c84..323c825 100644 --- a/lhost/via-courier.go +++ b/lhost/via-courier.go @@ -71,8 +71,7 @@ func init() { if sisimoji.ContainsAny(e, startingof["message"]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } f := rfc1894.Match(e); if f > 0 { // "e" matched with any field defined in RFC3464 @@ -160,8 +159,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } e.Command = thecommand diff --git a/lhost/via-domino.go b/lhost/via-domino.go index 688c660..388d4c6 100644 --- a/lhost/via-domino.go +++ b/lhost/via-domino.go @@ -70,8 +70,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Your message // @@ -169,9 +168,7 @@ func init() { if e.Reason != "" { break EXCEPTUTF8 } for _, f := range exceptutf8[r] { // Try to find an error message including lower-cased string listed in messagesof - if sisimoji.Aligned(e.Diagnosis, f) == false { continue } - e.Reason = r - break EXCEPTUTF8 + if sisimoji.Aligned(e.Diagnosis, f) { e.Reason = r; break EXCEPTUTF8 } } } } diff --git a/lhost/via-dragonfly.go b/lhost/via-dragonfly.go index 2e99c3a..c1a2e43 100644 --- a/lhost/via-dragonfly.go +++ b/lhost/via-dragonfly.go @@ -73,8 +73,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // This is the DragonFly Mail Agent v0.13 at df.example.jp. // @@ -120,8 +119,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-einsundeins.go b/lhost/via-einsundeins.go index 46881aa..f7e8ce6 100644 --- a/lhost/via-einsundeins.go +++ b/lhost/via-einsundeins.go @@ -47,8 +47,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if e == "" { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // The following address failed: // @@ -117,8 +116,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-exchange2003.go b/lhost/via-exchange2003.go index 9876b08..199ccec 100644 --- a/lhost/via-exchange2003.go +++ b/lhost/via-exchange2003.go @@ -50,8 +50,7 @@ func init() { for _, e := range bf.Headers["received"] { // Received: by ***.**.** with Internet Mail Service (5.5.2657.72) - if strings.Contains(e, tryto[3]) == false { continue } - proceedsto = true; break + if strings.Contains(e, tryto[3]) { proceedsto = true; break } } break } @@ -107,8 +106,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if statuspart == true { continue } + if readcursor & indicators["deliverystatus"] == 0 || statuspart == true { continue } if connvalues == len(connheader) { // did not reach the following recipient(s): @@ -195,10 +193,8 @@ func init() { if sisimoji.Aligned(e.Diagnosis, []string{"MSEXCH:", "(", ")"}) { // MSEXCH:IMS:KIJITORA CAT:EXAMPLE:EXCHANGE 0 (000C05A6) Unknown Recipient - p1 := strings.Index(e.Diagnosis, "(") - p2 := strings.Index(e.Diagnosis, ")") - capturedcode := e.Diagnosis[p1 + 1:p2] - errormessage := e.Diagnosis[p2 + 1:] + capturedcode := sisimoji.Select(e.Diagnosis, "(", ")", 0) + errormessage := e.Diagnosis[strings.Index(e.Diagnosis, ")") + 1:] FINDREASON: for r := range errorcodes { // The key name is a bounce reason name @@ -214,8 +210,7 @@ func init() { } // Could not detect the reason from the value of "diagnosis", copy alternative error message - if e.Reason != "" { continue } - if anotherone[j] == "" { continue } + if e.Reason != "" || anotherone[j] == "" { continue } e.Diagnosis = anotherone[j] + " " + e.Diagnosis e.Diagnosis = sisimoji.Sweep(e.Diagnosis) } diff --git a/lhost/via-exchange2007.go b/lhost/via-exchange2007.go index 3c1f963..7c8202a 100644 --- a/lhost/via-exchange2007.go +++ b/lhost/via-exchange2007.go @@ -95,8 +95,7 @@ func init() { if sisimoji.HasPrefixAny(e, startingof["message"]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if e == "" { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Diagnostic information for administrators: // @@ -121,8 +120,7 @@ func init() { if sisimoji.HasPrefixAny(e, startingof["rhost"]) { // Generating server: SG2APC01HT234.mail.protection.outlook.com // DSN generated by: NEKONYAAN0022.apcprd01.prod.exchangelabs.com - cv := rfc1123.Find(e) - if rfc1123.IsInternetHost(cv) { v.Rhost = cv } + if cv := rfc1123.Find(e); rfc1123.IsInternetHost(cv) { v.Rhost = cv } } else { // #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ## @@ -151,10 +149,7 @@ func init() { p2 := strings.Index(emailparts[0], "\nRecipient Address: "); if p2 < 0 { break } p3 := sisimoji.IndexOnTheWay(emailparts[0], "\n", p2 + 20); if p3 < 0 { break } cv := sisiaddr.S3S4(emailparts[0][p2 + 20:p3]) - - if rfc5322.IsEmailAddress(cv) == false { break } - dscontents[0].Recipient = cv - recipients++ + if rfc5322.IsEmailAddress(cv) { dscontents[0].Recipient = cv; recipients++ } } if recipients == 0 { return sis.RisingUnderway{} } @@ -172,8 +167,7 @@ func init() { if p0 < 0 || p1 < 0 { continue } // #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ## - cv := e.Diagnosis[p0 + 1:p1]; if len(ndrsubject[cv]) == 0 { continue } - e.Reason = ndrsubject[cv] + if cv := e.Diagnosis[p0 + 1:p1]; len(ndrsubject[cv]) > 0 { e.Reason = ndrsubject[cv] } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } diff --git a/lhost/via-exim.go b/lhost/via-exim.go index 806e42d..84483c3 100644 --- a/lhost/via-exim.go +++ b/lhost/via-exim.go @@ -51,8 +51,7 @@ func init() { // Subject: Mail delivery failed: returning message to sender // Subject: Mail delivery failed // Subject: Message frozen - if strings.Contains(bf.Headers["subject"][0], e) == false { continue } - proceedsto++; break + if strings.Contains(bf.Headers["subject"][0], e) { proceedsto++; break } } for { @@ -212,8 +211,7 @@ func init() { } } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // This message was created automatically by mail delivery software. // @@ -223,9 +221,7 @@ func init() { // kijitora@example.jp // SMTP error from remote mail server after RCPT TO:: // host neko.example.jp [192.0.2.222]: 550 5.1.1 ... User Unknown - cv := "" - ce := false - for { + ce := false; for { // Check whether the line matches the following conditions or not if strings.HasPrefix(e, " ") == false { break } // The line should start with " " (2 spaces) if strings.Index(e, "@") < 2 { break } // "@" should be included (email) @@ -237,7 +233,7 @@ func init() { ce = true; break } - if ce == true || sisimoji.ContainsAny(e, startingof["alias"]) { + if cv := ""; ce == true || sisimoji.ContainsAny(e, startingof["alias"]) { // The line is including an email address if sisimoji.ContainsAny(e, startingof["alias"]) { // The line does not include an email address @@ -250,9 +246,7 @@ func init() { // kijitora@example.jp // sabineko@example.jp: forced freeze // mikeneko@example.jp : ... - p1 := strings.Index(e, "<") - p2 := strings.Index(e, ">:") - if p1 > 1 && p2 > 1 { + cv = sisiaddr.S3S4(sisimoji.Select(e, "<", ">:", 0)); if cv != "" { // There are an email address and an error message in the line // parser.c:743| while (bracket_count-- > 0) if (*s++ != '>') // parser.c:744| { @@ -262,15 +256,14 @@ func init() { // parser.c:748| s-1, (int)(s - US mailbox - 1), mailbox); // parser.c:749| goto PARSE_FAILED; // parser.c:750| } - cv = sisiaddr.S3S4(e[p1:p2 + 1]) - v.Diagnosis = sisimoji.Sweep(e[p2 + 1:]) + v.Diagnosis = sisimoji.Sweep(e[strings.Index(e, ">:") + 1:]) } else { // There is an email address only in the line, such as " kijitora@example.jp" // --- OR --- // " kijitora@example.jp: forced freeze" - p3 := strings.LastIndex(e, ": "); if p3 < 0 { p3 = len(e) } - cv = sisiaddr.S3S4(e[2:p3]) + p1 := strings.LastIndex(e, ": "); if p1 < 0 { p1 = len(e) } + cv = sisiaddr.S3S4(e[2:p1]) } if rfc5322.IsEmailAddress(cv) == false { continue } } @@ -291,8 +284,7 @@ func init() { // generated by userx@myhost.test.ex for _, f := range strings.Split(e, " ") { // Get the alias adress - if strings.Contains(f, "@") == false { continue } - v.Alias = sisiaddr.S3S4(f); break + if strings.Contains(f, "@") { v.Alias = sisiaddr.S3S4(f); break } } } else { if sisimoji.ContainsAny(e, startingof["frozen"]) { @@ -310,8 +302,7 @@ func init() { if o[3] == "addr" { // Final-Recipient: rfc822;|/bin/echo "Some pipe output" - if o[0] != "final-recipient" { continue } - if v.Spec != "" { continue } + if o[0] != "final-recipient" || v.Spec != "" { continue } if strings.Contains(o[2], "@") { v.Spec = "SMTP" } else { v.Spec = "X-UNIX" } } else if o[3] == "code" { @@ -342,8 +333,7 @@ func init() { // domain part such as // pipe to |/path/to/prog ... // generated by kijitora@example.com - if strings.HasPrefix(e, " ") == false { continue } - v.Diagnosis += " " + e + if strings.HasPrefix(e, " ") { v.Diagnosis += " " + e } } } } @@ -365,11 +355,11 @@ func init() { if len(bf.Headers["x-failed-recipients"]) > 0 { // X-Failed-Recipients: kijitora@example.jp rcptinhead := strings.Split(bf.Headers["x-failed-recipients"][0], ",") - for j, _ := range rcptinhead { rcptinhead[j] = strings.Trim(rcptinhead[j], " ") } recipients = len(rcptinhead) for _, e := range rcptinhead { // Insert each recipient address into "dscontents" + e = strings.Trim(e, " ") dscontents[len(dscontents) - 1].Recipient = e if len(dscontents) == recipients { continue } dscontents = append(dscontents, sis.DeliveryMatter{}) @@ -430,7 +420,7 @@ func init() { } e.Diagnosis = sisimoji.Sweep(e.Diagnosis) - p1 := strings.Index(e.Diagnosis, "__"); if p1 > 1 { e.Diagnosis = e.Diagnosis[0:p1] } + if p1 := strings.Index(e.Diagnosis, "__"); p1 > 1 { e.Diagnosis = e.Diagnosis[0:p1] } if e.Rhost == "" { e.Rhost = rfc1123.Find(e.Diagnosis) } if e.Lhost == "" { e.Lhost = recvdtoken[0] } @@ -457,8 +447,7 @@ func init() { // Find any error message string defined in "messagesof" from e.Diagnosis for r := range messagesof { // The key is a bounce reason name - if sisimoji.ContainsAny(e.Diagnosis, messagesof[r]) == false { continue } - e.Reason = r; break + if sisimoji.ContainsAny(e.Diagnosis, messagesof[r]) { e.Reason = r; break } } if e.Reason == "" { @@ -486,18 +475,17 @@ func init() { // // The value of "Status:" indicates permanent error but the value of SMTP reply code in // Diagnostic-Code: field is "TEMPERROR"!!!! - re := e.Reason cr := reply.Find(e.Diagnosis, e.Status) cs := status.Find(e.Diagnosis, cr) cv := "" - if strings.HasPrefix(cr, "4") || re == "expired" || re == "mailboxfull" { + if strings.HasPrefix(cr, "4") || e.Reason == "expired" || e.Reason == "mailboxfull" { // Set the pseudo status code as a temporary error - cv = status.Code(re, true) + cv = status.Code(e.Reason, true) } else { // Set the pseudo status code as a permanent error - cv = status.Code(re, false) + cv = status.Code(e.Reason, false) } if e.ReplyCode == "" { e.ReplyCode = cr } if e.Status == "" { e.Status = status.Prefer(cs, cv, cr) } @@ -527,14 +515,14 @@ func init() { // and when that happens, the message will be returned to you. emailparts[1] += fmt.Sprintf("To: <%s>\n", dscontents[0].Recipient) - p1 := strings.Index(bf.Payload, "The date of the message is: "); if p1 < 0 { break } - p2 := sisimoji.IndexOnTheWay(bf.Payload, "\n", p1); if p2 < 0 { break } - emailparts[1] += fmt.Sprintf("Date: %s\n", bf.Payload[p1 + 31:p2]) - - p1 = strings.Index(bf.Payload, "The subject of the message is: "); if p1 < 0 { break } - p2 = sisimoji.IndexOnTheWay(bf.Payload, "\n", p1); if p2 < 0 { break } - emailparts[1] += fmt.Sprintf("Subject: %s\n", bf.Payload[p1 + 31:p2]) - break + if cv := sisimoji.Select(bf.Payload, "The date of the message is: ", "\n", 0); cv != "" { + // The date of the message is: Thu, 22 Apr 2016 23:34:45 +0900 + emailparts[1] += fmt.Sprintf("Date: %s\n", strings.Trim(cv, " ")) + } + if cv := sisimoji.Select(bf.Payload, "The subject of the message is: ", "\n", 0); cv != "" { + // The date of the message is: Thu, 22 Apr 2016 23:34:45 +0900 + emailparts[1] += fmt.Sprintf("Subject: %s\n", strings.Trim(cv, " ")) + } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } } diff --git a/lhost/via-ezweb.go b/lhost/via-ezweb.go index 5eb81c5..4944aef 100644 --- a/lhost/via-ezweb.go +++ b/lhost/via-ezweb.go @@ -83,8 +83,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if sisimoji.HasPrefixAny(e, startingof["message"]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // The user(s) account is disabled. // @@ -100,20 +99,17 @@ func init() { if sisimoji.Aligned(e, []string{"<", "@", ">"}) && (strings.Index(e, "Recipient: <") > 1 || strings.HasPrefix(e, "<")) { // Recipient: <******@ezweb.ne.jp> OR <***@ezweb.ne.jp>: 550 user unknown ... - p1 := strings.Index(e, "<") - p2 := strings.Index(e, ">") - if len(v.Recipient) > 0 { // There are multiple recipient addresses in the message body. dscontents = append(dscontents, sis.DeliveryMatter{}) v = &(dscontents[len(dscontents) - 1]) } - v.Recipient = sisiaddr.S3S4(e[p1 + 1:p2]) + v.Recipient = sisiaddr.S3S4(sisimoji.Select(e, "<", ">", 0)) v.Diagnosis += " " + e recipients += 1 } else { - f := rfc1894.Match(e); if f > 0 { + if f := rfc1894.Match(e); f > 0 { // "e" matched with any field defined in RFC3464 o := rfc1894.Field(e); if len(o) == 0 { continue } v.Update(v.AsRFC1894(o[0]), o[2]) @@ -132,8 +128,7 @@ func init() { } else { // Check the error message - isincluded := false - for _, r := range substrings { + isincluded := false; for _, r := range substrings { // Try to find that the line contains any error message text if strings.Contains(e, r) == false { continue } v.Diagnosis += " " + e @@ -163,8 +158,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-fml.go b/lhost/via-fml.go index ff74726..89218b3 100644 --- a/lhost/via-fml.go +++ b/lhost/via-fml.go @@ -61,18 +61,16 @@ func init() { for _, e := range(strings.Split(emailparts[0], "\n")) { // Read error messages and delivery status lines from the head of the email to the // previous line of the beginning of the original message. - if len(e) == 0 { continue } + if e == "" { continue } - p1 := strings.Index(e, "<") - p2 := strings.Index(e, ">") - if p1 > 0 && p2 > 0 { + if cv := sisimoji.Select(e, "<", ">", 0); cv != "" { // You are not a member of this mailing list . if len(v.Recipient) > 0 { // There are multiple recipient addresses in the message body. dscontents = append(dscontents, sis.DeliveryMatter{}) v = &(dscontents[len(dscontents) - 1]) } - v.Recipient = e[p1:p2] + v.Recipient = cv v.Diagnosis = e recipients += 1 @@ -90,15 +88,13 @@ func init() { for f := range errortable { // The key is a bounce reason name - if sisimoji.ContainsAny(e.Diagnosis, errortable[f]) == false { continue } - e.Reason = f; break + if sisimoji.ContainsAny(e.Diagnosis, errortable[f]) { e.Reason = f; break } } if e.Reason != "" { continue } for f := range errortitle { // The key is a bounce reason name - if sisimoji.ContainsAny(bf.Headers["subject"][0], errortitle[f]) == false { continue } - e.Reason = f; break + if sisimoji.ContainsAny(bf.Headers["subject"][0], errortitle[f]) { e.Reason = f; break } } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } diff --git a/lhost/via-gmail.go b/lhost/via-gmail.go index 4edbf3e..9233fdc 100644 --- a/lhost/via-gmail.go +++ b/lhost/via-gmail.go @@ -174,8 +174,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Technical details of permanent failure:=20 // Google tried to deliver your message, but it was rejected by the recipient = @@ -203,9 +202,7 @@ func init() { v = &(dscontents[len(dscontents) - 1]) } cv := sisiaddr.S3S4(strings.Trim(e, " ")) - if rfc5322.IsEmailAddress(cv) == false { continue } - v.Recipient = cv - recipients += 1 + if rfc5322.IsEmailAddress(cv) == true { v.Recipient = cv; recipients++ } } else { // Error message lines except " neko@example.jp" line @@ -220,34 +217,27 @@ func init() { e.Diagnosis = sisimoji.Sweep(e.Diagnosis) e.Rhost = rfc1123.Find(e.Diagnosis) - for { + if cv := sisimoji.Select(e.Diagnosis, " (state ", ")", 0); len(statetable[cv]) > 0 { // Find "(state 18)" and pick "18" as a key of statetable - p1 := strings.LastIndex(e.Diagnosis, " (state "); if p1 < 0 { break } - p2 := strings.LastIndex(e.Diagnosis, ")"); if p2 < 0 { break } - if p1 > p2 { break } - cu := e.Diagnosis[p1 + 8:p2]; if len(statetable[cu]) == 0 { break } - e.Command = statetable[cu][0] - e.Reason = statetable[cu][1] - break + e.Command = statetable[cv][0] + e.Reason = statetable[cv][1] } + if e.Reason == "" { // There is no state code in the error message FINDREASON: for r := range messagesof { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } if e.Reason == "" { continue } // Set a pseudo status code and override the bounce reason - e.Status = status.Find(e.Diagnosis, e.ReplyCode) - - if e.Status == "" || strings.Contains(e.Status, ".0") { continue } - e.Reason = status.Name(e.Status) + e.Status = status.Find(e.Diagnosis, e.ReplyCode); if e.Status == "" { continue } + if strings.Contains(e.Status, ".0") == false { e.Reason = status.Name(e.Status) } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } } diff --git a/lhost/via-gmx.go b/lhost/via-gmx.go index 0fb6905..d98cbcf 100644 --- a/lhost/via-gmx.go +++ b/lhost/via-gmx.go @@ -49,8 +49,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // This message was created automatically by mail delivery software. // @@ -87,8 +86,7 @@ func init() { } else { // Get error messages - if e == "" { continue } - v.Diagnosis += e + " " + if e != "" { v.Diagnosis += e + " " } } } if recipients == 0 { return sis.RisingUnderway{} } @@ -102,8 +100,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-googleworkspace.go b/lhost/via-googleworkspace.go index 26a4ee3..f314e99 100644 --- a/lhost/via-googleworkspace.go +++ b/lhost/via-googleworkspace.go @@ -21,9 +21,9 @@ func init() { // @param *sis.BeforeFact bf Message body of a bounce email // @return RisingUnderway RisingUnderway structure // @see https://workspace.google.com/ - if bf == nil || bf.Empty() == true { return sis.RisingUnderway{} } - if strings.Contains(bf.Payload, "\nDiagnostic-Code:") == true { return sis.RisingUnderway{} } - if strings.Contains(bf.Payload, "\nFinal-Recipient:") == true { return sis.RisingUnderway{} } + if bf == nil || bf.Empty() == true { return sis.RisingUnderway{} } + if strings.Contains(bf.Payload, "\nDiagnostic-Code:") == true { return sis.RisingUnderway{} } + if strings.Contains(bf.Payload, "\nFinal-Recipient:") == true { return sis.RisingUnderway{} } if strings.Contains(bf.Headers["from"][0], "") == false { return sis.RisingUnderway{} } if strings.Contains(bf.Headers["subject"][0], "Delivery Status Notification") == false { return sis.RisingUnderway{} } @@ -56,8 +56,7 @@ func init() { } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // ** Message not delivered ** // You're sending this from a different address or alias using the 'Send mail as' feature. @@ -65,18 +64,16 @@ func init() { // Learn more here: https://support.google.com/mail/?p=CustomFromDenied // The response was: // Unspecified Error (SENT_SECOND_EHLO): Smtp server does not advertise AUTH capability - if strings.HasPrefix(e, "Content-Type:") == true { continue } - v.Diagnosis += e + " " + if strings.HasPrefix(e, "Content-Type:") == false { v.Diagnosis += e + " " } } - for recipients == 0 { - // Pick the recipient address from the value of To: header of the original message after - // Content-Type: message/rfc822 field - p0 := strings.Index(emailparts[1], "\nTo:"); if p0 < 0 { break } - p1 := sisimoji.IndexOnTheWay(emailparts[1], "\n", p0 + 2) - cv := sisiaddr.S3S4(emailparts[1][p0 + 4:p1]); if cv == "" { break } - dscontents[0].Recipient = cv - recipients++ + if recipients == 0 { + // Pick the recipient address from the value of To: header of the original message + // after Content-Type: message/rfc822 field + if cv := sisiaddr.S3S4(sisimoji.Select(emailparts[1], "\nTo:", "\n", 0)); cv != "" { + dscontents[0].Recipient = cv + recipients++ + } } if recipients == 0 { return sis.RisingUnderway{} } @@ -89,8 +86,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-imailserver.go b/lhost/via-imailserver.go index 37ed939..00d8a1c 100644 --- a/lhost/via-imailserver.go +++ b/lhost/via-imailserver.go @@ -47,8 +47,7 @@ func init() { for _, e := range(strings.Split(emailparts[0], "\n")) { // Read error messages and delivery status lines from the head of the email to the // previous line of the beginning of the original message. - p0 := strings.Index(e, ": ") - if (p0 > 8 && sisimoji.Aligned(e, []string{": ", "@"})) || strings.HasPrefix(e, "undeliverable ") { + if (strings.Index(e, ": ") > 8 && sisimoji.Aligned(e, []string{": ", "@"})) || strings.HasPrefix(e, "undeliverable ") { // Unknown user: kijitora@example.com // undeliverable to kijitora@example.com if len(v.Recipient) > 0 { @@ -68,8 +67,7 @@ func init() { } else { // Error message after "Body of message generated response:" line - if alternates == "" { continue } - alternates += " " + e + if alternates != "" { alternates += " " + e } } } } @@ -91,8 +89,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-interscanmss.go b/lhost/via-interscanmss.go index f66bfa7..2a7395a 100644 --- a/lhost/via-interscanmss.go +++ b/lhost/via-interscanmss.go @@ -22,8 +22,7 @@ func init() { // @return RisingUnderway RisingUnderway structure if bf == nil || bf.Empty() == true { return sis.RisingUnderway{} } - proceedsto := false - for { + proceedsto := false; for { emailtitle := bf.Headers["subject"][0] titletable := []string{ "Mail could not be delivered", @@ -84,8 +83,7 @@ func init() { } else if p1 > 0 || p2 > 0 { // Error messages are not written in English if strings.Contains(e, " >>> ") { v.Command = command.Find(e) } - p3 := strings.Index(e, " <<< "); if p3 < 0 { continue } - v.Diagnosis = e[p3 + 4:] + if p3 := strings.Index(e, " <<< "); p3 > -1 { v.Diagnosis = e[p3 + 4:] } } } if recipients == 0 { return sis.RisingUnderway{} } diff --git a/lhost/via-kddi.go b/lhost/via-kddi.go index 6eca805..4cdca3a 100644 --- a/lhost/via-kddi.go +++ b/lhost/via-kddi.go @@ -62,8 +62,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } if strings.Contains(e, " Could not be delivered to: <") { // Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900 @@ -75,9 +74,7 @@ func init() { v = &(dscontents[len(dscontents) - 1]) } cv := sisiaddr.S3S4(e[strings.Index(e, "<"):]) - if rfc5322.IsEmailAddress(cv) == false { continue } - v.Recipient = cv - recipients += 1 + if rfc5322.IsEmailAddress(cv) { v.Recipient = cv; recipients++ } } else if strings.Contains(e, "Your mail sent on: ") { // Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900 @@ -109,8 +106,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-mailfoundry.go b/lhost/via-mailfoundry.go index 0fee1fa..5374380 100644 --- a/lhost/via-mailfoundry.go +++ b/lhost/via-mailfoundry.go @@ -20,15 +20,14 @@ func init() { // @return RisingUnderway RisingUnderway structure if bf == nil || bf.Empty() == true { return sis.RisingUnderway{} } - proceedsto := false - ISMF: for { + proceedsto := false; for { // Subject: Message delivery has failed - if bf.Headers["subject"][0] != "Message delivery has failed" { break ISMF } + if bf.Headers["subject"][0] != "Message delivery has failed" { break } for _, e := range bf.Headers["received"] { // Received: From localhost (127.0.0.1) by smtp9.mf.example.ne.jp (MAILFOUNDRY) id ... - if strings.Contains(e, "(MAILFOUNDRY) id") { proceedsto = true; break ISMF } + if strings.Contains(e, "(MAILFOUNDRY) id") { proceedsto = true; break } } - break ISMF + break } if proceedsto == false { return sis.RisingUnderway{} } @@ -51,8 +50,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Unable to deliver message to: // Delivery failed for the following reason: @@ -71,9 +69,8 @@ func init() { } else { // Error messages - if e == startingof["error"][0] { v.Diagnosis = e; continue } - if v.Diagnosis == "" { continue } - if strings.HasPrefix(e, "-") { continue } + if e == startingof["error"][0] { v.Diagnosis = e; continue } + if v.Diagnosis == "" || strings.HasPrefix(e, "-") { continue } v.Diagnosis += " " + e } } diff --git a/lhost/via-mailmarshalsmtp.go b/lhost/via-mailmarshalsmtp.go index 147a7a0..278416b 100644 --- a/lhost/via-mailmarshalsmtp.go +++ b/lhost/via-mailmarshalsmtp.go @@ -90,27 +90,24 @@ func init() { // Reporting-MTA: // MessageName: // Last-Attempt-Date: <16:21:07 seg, 22 Dezembro 2014> - p1 := strings.Index(e, "<"); if p1 < 0 { continue } - p2 := strings.Index(e, ">"); if p2 < 0 { continue } - if strings.HasPrefix(e, "Original Sender: ") { // Original Sender: // Use this line instead of "From" header of the original message. - emailparts[1] += fmt.Sprintf("From: %s\n", e[p1 + 1:p2]) + emailparts[1] += fmt.Sprintf("From: %s\n", sisimoji.Select(e, "<", ">", 0)) } else if strings.HasPrefix(e, "Sender-MTA: ") { // Sender-MTA: <10.11.12.13> - v.Lhost = e[p1 + 1:p2] + v.Lhost = sisimoji.Select(e, "<", ">", 0) } else if strings.HasPrefix(e, "Reporting-MTA: ") { // Reporting-MTA: - v.Rhost = e[p1 + 1:p2] + v.Rhost = sisimoji.Select(e, "<", ">", 0) } else if strings.Contains(e, " From:") || strings.Contains(e, " Subject:") { // From: originalsender@example.com // Subject: ... - p1 = strings.Index(e, " From:"); if p1 < 0 { p1 = strings.Index(e, " Subject:") } - p2 = strings.Index(e, ":") + p1 := strings.Index(e, " From:"); if p1 < 0 { p1 = strings.Index(e, " Subject:") } + p2 := strings.Index(e, ":") emailparts[1] += fmt.Sprintf("%s: %s\n", e[p1 + 1:p2], sisimoji.Sweep(e[p2 + 1:])) } } diff --git a/lhost/via-messagingserver.go b/lhost/via-messagingserver.go index 12519e3..3b7b5cd 100644 --- a/lhost/via-messagingserver.go +++ b/lhost/via-messagingserver.go @@ -10,6 +10,7 @@ package lhost import "strings" import "libsisimai.org/sisimai/sis" +import "libsisimai.org/sisimai/rfc791" import "libsisimai.org/sisimai/rfc1894" import "libsisimai.org/sisimai/rfc5322" import "libsisimai.org/sisimai/smtp/reply" @@ -49,8 +50,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // --Boundary_(ID_0000000000000000000000) // Content-type: text/plain; charset=us-ascii @@ -105,18 +105,14 @@ func init() { } else if strings.HasPrefix(e, " Remote system: ") { // Remote system: dns;mx.example.jp (TCP|17.111.174.67|47323|192.0.2.225|25) // (6jo.example.jp ESMTP SENDMAIL-VM) - p1 := strings.Index(e, ";"); if p1 < 0 { continue } - p2 := strings.Index(e, "("); if p2 < 0 { continue } - v.Rhost = e[p1 + 1:p2 - 1] - - // The value does not include ".", use IP address instead. - // (TCP|17.111.174.67|47323|192.0.2.225|25) - ss := strings.Split(e[p2 + 1:], "|") - if len(ss) == 0 || ss[0] != "TCP" { continue } - if len(ss) > 1 { v.Lhost = ss[1] } - if strings.Contains(v.Rhost, ".") { continue } - if len(ss) > 3 { v.Rhost = ss[3] } + v.Rhost = sisimoji.Select(e, ";", " (", 0); if v.Rhost == "" { continue } + if cv := strings.Split(sisimoji.Select(e, " (", ")", 0), "|"); len(cv) == 5 { + // (TCP|17.111.174.67|47323|192.0.2.225|25) + if cv[0] != "TCP" || strings.Contains(v.Rhost, ".") { continue } + if rfc791.IsIPv4Address(cv[1]) { v.Lhost = cv[1] } + if rfc791.IsIPv4Address(cv[3]) { v.Rhost = cv[3] } + } } else { // Original-envelope-id: 0NFC009FLKOUVMA0@mr21p30im-asmtp004.me.com // Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon) @@ -140,9 +136,8 @@ func init() { } else if strings.HasPrefix(e, "Reporting-MTA: ") { // Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon) - if strings.Contains(v.Lhost, ".") { continue } - f := rfc1894.Field(e); if len(f) == 0 { continue } - v.Lhost = f[2] + if strings.Contains(v.Lhost, ".") { continue } + if f := rfc1894.Field(e); len(f) > 0 { v.Lhost = f[2] } } } } @@ -157,8 +152,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-mfilter.go b/lhost/via-mfilter.go index 318588c..c13e4ee 100644 --- a/lhost/via-mfilter.go +++ b/lhost/via-mfilter.go @@ -46,8 +46,7 @@ func init() { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // このメールは「m-FILTER」が自動的に生成して送信しています。 // メールサーバーとの通信中、下記の理由により diff --git a/lhost/via-notes.go b/lhost/via-notes.go index 94c610e..f4c388c 100644 --- a/lhost/via-notes.go +++ b/lhost/via-notes.go @@ -46,8 +46,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // ------- Failure Reasons -------- // @@ -72,13 +71,11 @@ func init() { } } - for recipients == 0 { + if recipients == 0 { // Pick an email address from "To:" header of the original message - p0 := strings.Index(emailparts[1], "\n\n"); if p0 < 0 { p0 = len(emailparts[1]) } - p1 := strings.Index(emailparts[1], "\nTo:"); if p1 < 0 || p1 > p0 { break } - p2 := strings.Index(emailparts[1][p1 + 4:], "\n") - cv := sisiaddr.S3S4(emailparts[1][p1 + 4:p1 + p2 + 4]) - dscontents[0].Recipient = cv; recipients++; break + if cv := sisimoji.Select(emailparts[1], "\nTo:", "\n", 0); cv != "" { + dscontents[0].Recipient = sisiaddr.S3S4(cv); recipients++ + } } if recipients == 0 { return sis.RisingUnderway{} } @@ -91,8 +88,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-opensmtpd.go b/lhost/via-opensmtpd.go index f14a285..940b658 100644 --- a/lhost/via-opensmtpd.go +++ b/lhost/via-opensmtpd.go @@ -111,8 +111,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Hi! // @@ -147,8 +146,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-postfix.go b/lhost/via-postfix.go index 78b484a..3ccc3ac 100644 --- a/lhost/via-postfix.go +++ b/lhost/via-postfix.go @@ -71,7 +71,6 @@ func init() { for _, e := range transcript { // Pick email addresses, error messages, and the last SMTP command. v = &(dscontents[len(dscontents) - 1]) - p := e.Response if e.Command == "EHLO" || e.Command == "HELO" { // Use the argument of EHLO/HELO command as a value of "lhost" @@ -91,13 +90,12 @@ func init() { v.Recipient = e.Argument recipients += 1 } - reply, nyaan := strconv.ParseUint(p.Reply, 10, 16) - if nyaan != nil || reply < 400 { continue } + if reply, nyaan := strconv.ParseUint(e.Response.Reply, 10, 16); nyaan != nil || reply < 400 { continue } commandset = append(commandset, e.Command) - if len(v.Diagnosis) == 0 { v.Diagnosis = strings.Join(p.Text, " ") } - if len(v.ReplyCode) == 0 { v.ReplyCode = p.Reply } - if len(v.Status) == 0 { v.Status = p.Status } + if len(v.Diagnosis) == 0 { v.Diagnosis = strings.Join(e.Response.Text, " ") } + if len(v.ReplyCode) == 0 { v.ReplyCode = e.Response.Reply } + if len(v.Status) == 0 { v.Status = e.Response.Status } } } else { // The message body is a general bounce mail message of Postfix @@ -119,7 +117,7 @@ func init() { } if readcursor & indicators["deliverystatus"] == 0 { continue } - f := rfc1894.Match(e); if f > 0 { + if f := rfc1894.Match(e); f > 0 { // "e" matched with any field defined in RFC3464 o := rfc1894.Field(e); if len(o) == 0 { continue } z := fieldtable[o[0]] @@ -144,8 +142,7 @@ func init() { } } else if o[3] == "code" { // Diagnostic-Code: SMTP; 550 5.1.1 ... User Unknown - v.Spec = o[1] - if strings.ToUpper(o[1]) == "X-POSTFIX" { v.Spec = "SMTP" } + v.Spec = o[1]; if strings.ToUpper(o[1]) == "X-POSTFIX" { v.Spec = "SMTP" } v.Diagnosis = o[2] } else { @@ -178,21 +175,16 @@ func init() { if strings.Contains(e, "(in reply to ") || strings.Contains(e, "command)") { // Find an SMTP command from a string like the following: // 5.1.1 ... User Unknown (in reply to RCPT TO - cv := command.Find(e) - if len(cv) > 0 { commandset = append(commandset, cv) } - if len(anotherset["diagnosis"]) > 0 { anotherset["diagnosis"] += " " + e } + if cv := command.Find(e); len(cv) > 0 { commandset = append(commandset, cv) } + if len(anotherset["diagnosis"]) > 0 { anotherset["diagnosis"] += " " + e } } else if sisimoji.Aligned(e, []string{"<", "@", ">", "(expanded from <", "):"}) { // (expanded from ): user ... // OR // : ... - p1 := strings.Index(e, "> ") - p2 := strings.Index(e[p1:], "(expanded from ") - p3 := strings.Index(e[p2 + 14:], ">):") - p4 := p3 + p2 + 14 + 3 // len("(expanded from ") + len(">):") - anotherset["recipient"] = sisiaddr.S3S4(e[0:p1]) - anotherset["alias"] = sisiaddr.S3S4(e[p2 + 15:]) - if len(e) > p4 { anotherset["diagnosis"] = e[p4:] } + anotherset["recipient"] = sisiaddr.S3S4(sisimoji.Select(e, "<", "< ", 0)) + anotherset["alias"] = sisiaddr.S3S4(sisimoji.Select(e, "(expanded from ", "):", 0)) + if p1 := strings.Index(e, ">): ") + 4; len(e) > p1 { anotherset["diagnosis"] = e[p1:] } } else if strings.HasPrefix(e, "<") && sisimoji.Aligned(e, []string{"<", "@", ">:"}) { // : ... @@ -228,21 +220,13 @@ func init() { v.Recipient = anotherset["recipient"] recipients += 1 - } else { + } else if nomessages == true { // Get a recipient address from message/rfc822 part if the delivery report was unavailable: // "--- Delivery report unavailable ---" - for { - p1 := strings.Index(emailparts[1], "\nTo: ") - if nomessages == false { break } - if p1 < 1 { break } - if p1 + 6 > len(emailparts[1]) { break } - + if cv := sisiaddr.S3S4(sisimoji.Select(emailparts[1], "\nTo: ", "\n", 0)); cv != "" { // Try to get a recipient address from To: field in the original message at message/rfc822 part - p2 := sisimoji.IndexOnTheWay(emailparts[1], "\n", p1 + 1) - cv := emailparts[1][p1 + 5:p2 + 1] - dscontents[len(dscontents) - 1].Recipient = sisiaddr.S3S4(cv) + dscontents[len(dscontents) - 1].Recipient = cv recipients += 1 - break } } } diff --git a/lhost/via-qmail.go b/lhost/via-qmail.go index 1b42f97..9918ade 100644 --- a/lhost/via-qmail.go +++ b/lhost/via-qmail.go @@ -177,8 +177,7 @@ func init() { if sisimoji.ContainsAny(e, startingof["message"]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // : // 192.0.2.153 does not like recipient. @@ -207,11 +206,7 @@ func init() { // Connected to 192.0.2.112 but my name was rejected. // Giving up on 192.0.2.135. // remote host 203.138.180.112 said:... - p1 := strings.Index(e, r); if p1 < 0 { continue } - cm := len(r) - p2 := sisimoji.IndexOnTheWay(e, " ", p1 + cm + 1); if p2 < 0 { p2 = strings.LastIndex(e, ".") } - v.Rhost = sisimoji.Sweep(e[p1 + cm:p2]) - break + if cv := sisimoji.Select(e + " ", r, " ", 0); cv != "" { v.Rhost = sisimoji.Sweep(cv); break } } } } @@ -248,16 +243,12 @@ func init() { if f == "" { continue } for r := range messagesof { // The key name is a bounce reason name - if sisimoji.ContainsAny(f, messagesof[r]) == false { continue } - e.Reason = r - break FINDREASON + if sisimoji.ContainsAny(f, messagesof[r]) { e.Reason = r; break FINDREASON } } for r := range failonldap { // The key name is a bounce reason name - if sisimoji.ContainsAny(f, failonldap[r]) == false { continue } - e.Reason = r - break FINDREASON + if sisimoji.ContainsAny(f, failonldap[r]) { e.Reason = r; break FINDREASON } } if strings.Contains(f, hasexpired) { e.Reason = "expired" } } diff --git a/lhost/via-sendmail.go b/lhost/via-sendmail.go index 0fb54bb..36488df 100644 --- a/lhost/via-sendmail.go +++ b/lhost/via-sendmail.go @@ -74,7 +74,7 @@ func init() { } if readcursor & indicators["deliverystatus"] == 0 { continue } - f := rfc1894.Match(e); if f > 0 { + if f := rfc1894.Match(e); f > 0 { // "e" matched with any field defined in RFC3464 o := rfc1894.Field(e); if len(o) == 0 { continue } z := fieldtable[o[0]] @@ -200,8 +200,7 @@ func init() { for { // Replace or append the error message in "diagnosis" with the ESMTP Reply Code // when the following conditions have matched - if len(esmtpreply) == 0 { break } - if recipients != 1 { break } + if len(esmtpreply) == 0 || recipients != 1 { break } e.Diagnosis = fmt.Sprintf("%s %s", strings.Join(esmtpreply, " "), e.Diagnosis) break @@ -211,20 +210,13 @@ func init() { if e.Command == "" { e.Command = command.Find(e.Diagnosis) } if e.Command == "" { if len(esmtpreply) > 0 { e.Command = "EHLO" }} - for { - // Check alternative status code and override it - if len(anotherset["status"]) == 0 { break } - if status.Test(e.Status) == true { break } - - e.Status = anotherset["status"] - break - } + // Check alternative status code and override it + if len(anotherset["status"]) > 0 && status.Test(e.Status) == false { e.Status = anotherset["status"] } if strings.HasPrefix(e.Recipient, "@") { // There is no local part in the recipient address such as "@mail.example.org" // Get the email address from the value of Diagnostic-Code field - cv := sisiaddr.Find(e.Diagnosis) - if cv[0] != "" { e.Recipient = cv[0] } + if cv := sisiaddr.Find(e.Diagnosis); cv[0] != "" { e.Recipient = cv[0] } } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } diff --git a/lhost/via-v5sendmail.go b/lhost/via-v5sendmail.go index 49063e2..06ff49d 100644 --- a/lhost/via-v5sendmail.go +++ b/lhost/via-v5sendmail.go @@ -63,8 +63,7 @@ func init() { if strings.Contains(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // ----- Transcript of session follows ----- // While talking to smtp.example.com: @@ -76,10 +75,8 @@ func init() { if sisimoji.Aligned(e, []string{" <", "@", ">..."}) || strings.Contains(strings.ToUpper(e), ">>> RCPT TO:") { // 550 ... User unknown // >>> RCPT To: - p0 := strings.Index(e, " ") - p1 := sisimoji.IndexOnTheWay(e, "<", p0) - p2 := sisimoji.IndexOnTheWay(e, ">", p1) - cv := sisiaddr.S3S4(e[p1:p2 + 1]) + ce := sisimoji.Select(e, " <", ">...", 0); if ce == "" { ce = sisimoji.Select(e, ":<", ">", 0) } + cv := sisiaddr.S3S4(ce) // Keep error messages before "While talking to ..." line if remotehost == "" { anotherone[recipients] += " " + e; continue } @@ -145,12 +142,8 @@ func init() { if recipients == 0 { // Try to pick an recipient address from the original message - p1 := strings.Index(emailparts[1], "\nTo: ") - p2 := sisimoji.IndexOnTheWay(emailparts[1], "\n", p1 + 6) - - if p1 > 0 { + if cv := sisimoji.Select(emailparts[1], "\nTo: ", "\n", 0); cv != "" { // Get the recipient address from "To:" header at the original message - cv := sisiaddr.S3S4(emailparts[1][p1 + 5:p2]) if rfc5322.IsEmailAddress(cv) == false { return sis.RisingUnderway{} } dscontents[0].Recipient = cv; recipients++ } diff --git a/lhost/via-verizon.go b/lhost/via-verizon.go index 48adf89..629e9c1 100644 --- a/lhost/via-verizon.go +++ b/lhost/via-verizon.go @@ -58,8 +58,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } v.Diagnosis += e } @@ -78,8 +77,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/lhost/via-x1.go b/lhost/via-x1.go index 48aeb5e..59e8928 100644 --- a/lhost/via-x1.go +++ b/lhost/via-x1.go @@ -39,8 +39,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // The original message was received at Thu, 29 Apr 2010 23:34:45 +0900 (JST) // from shironeko@example.jp @@ -79,13 +78,10 @@ func init() { e := &(dscontents[j]) e.Diagnosis = sisimoji.Sweep(e.Diagnosis) - for e.Date == "" { + if e.Date == "" { // The original message was received at Thu, 29 Apr 2010 23:34:45 +0900 (JST) // from shironeko@example.jp - p1 := strings.Index(e.Diagnosis, " at "); if p1 < 0 { break } - p2 := strings.Index(e.Diagnosis, "from"); if p2 < 0 { break } - e.Date = e.Diagnosis[p1 + 4:p2 - 1] - break + e.Date = strings.Trim(sisimoji.Select(e.Diagnosis, " at ", "from", 0), " ") } } return sis.RisingUnderway{ Digest: dscontents, RFC822: emailparts[1] } diff --git a/lhost/via-x2.go b/lhost/via-x2.go index 4d7aaac..02d80d5 100644 --- a/lhost/via-x2.go +++ b/lhost/via-x2.go @@ -46,8 +46,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // Message from example.com. // Unable to deliver message to the following address(es). diff --git a/lhost/via-x3.go b/lhost/via-x3.go index 5b061c7..1c8a48f 100644 --- a/lhost/via-x3.go +++ b/lhost/via-x3.go @@ -46,8 +46,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // ============================================================================ // This is an automatically generated Delivery Status Notification. diff --git a/lhost/via-x6.go b/lhost/via-x6.go index 9578a68..4f9e1e5 100644 --- a/lhost/via-x6.go +++ b/lhost/via-x6.go @@ -40,8 +40,7 @@ func init() { // Beginning of the bounce message or message/delivery-status part if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // We had trouble delivering your message. Full details follow: // diff --git a/lhost/via-zoho.go b/lhost/via-zoho.go index 5ce3c5c..2234348 100644 --- a/lhost/via-zoho.go +++ b/lhost/via-zoho.go @@ -43,8 +43,7 @@ func init() { if strings.HasPrefix(e, startingof["message"][0]) { readcursor |= indicators["deliverystatus"] } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if len(e) == 0 { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } // This message was created automatically by mail delivery software. // A message that you sent could not be delivered to one or more of its recip= @@ -86,8 +85,7 @@ func init() { // The key name is a bounce reason name for _, f := range messagesof[r] { // Try to find an error message including lower-cased string listed in messagesof - if strings.Contains(e.Diagnosis, f) == false { continue } - e.Reason = r; break FINDREASON + if strings.Contains(e.Diagnosis, f) { e.Reason = r; break FINDREASON } } } } diff --git a/message/rise.go b/message/rise.go index f7d6644..0477aa3 100644 --- a/message/rise.go +++ b/message/rise.go @@ -57,8 +57,7 @@ func Rise(mesg *string, hook sis.CfParameter0) *sis.BeforeFact { RISE: for retryagain < 2 { // 1. Split email data to headers and a body part. - email, nyaan := mail.ReadMessage(strings.NewReader(*mesg)) - if nyaan != nil { + if email, nyaan := mail.ReadMessage(strings.NewReader(*mesg)); nyaan != nil { // Failed to read the message as an email ce := *sis.MakeNotDecoded(fmt.Sprintf("%s", nyaan), true) beforefact.Errors = append(beforefact.Errors, ce) diff --git a/message/sift.go b/message/sift.go index 368d891..a0624e2 100644 --- a/message/sift.go +++ b/message/sift.go @@ -87,8 +87,7 @@ func sift(bf *sis.BeforeFact, hook sis.CfParameter0) bool { if havecalled[r] || r == "ARF" || strings.HasPrefix(r, "RFC") { continue } localhostr = lhost.InquireFor[r](bf) havecalled[r] = true - modulename = r - if localhostr.Void() == false { break DECODER } + if localhostr.Void() == false { modulename = r; break DECODER } } if havecalled["rfc3464"] == false { @@ -96,24 +95,21 @@ func sift(bf *sis.BeforeFact, hook sis.CfParameter0) bool { // When the all of sisimai/lhost/*.go modules did not return the decoded data localhostr = rfc3464.Inquire(bf) havecalled["rfc3464"] = true - modulename = "RFC3464" - if localhostr.Void() == false { break DECODER } + if localhostr.Void() == false { modulename = "RFC3464"; break DECODER } } if havecalled["arf"] == false { // 3. call sisimai/arf // Try to decode the message as a Feedback Loop message localhostr = arf.Inquire(bf) - modulename = "ARF" - if localhostr.Void() == false { break DECODER } + if localhostr.Void() == false { modulename = "ARF"; break DECODER } } if havecalled["rfc3834"] == false { // 4. call sisimai/rfc3834 // Try to sift the message as auto reply message defined in RFC3834 localhostr = rfc3834.Inquire(bf) - modulename = "RFC3834" - if localhostr.Void() == false { break DECODER } + if localhostr.Void() == false { modulename = "RFC3834"; break DECODER } } break // as of now, we have no sample email for coding this block @@ -122,8 +118,7 @@ func sift(bf *sis.BeforeFact, hook sis.CfParameter0) bool { for j, _ := range localhostr.Digest { // Set the value of "Agent" such as "Postfix", "Sendmail", or "OpenSMTPD" - if localhostr.Digest[j].Agent != "" { continue } - localhostr.Digest[j].Agent = modulename + if localhostr.Digest[j].Agent == "" { localhostr.Digest[j].Agent = modulename } } if strings.Contains(localhostr.RFC822, "\nFrom:") == false && len(bf.Headers["to"]) > 0 { diff --git a/message/tidy.go b/message/tidy.go index aec5578..c33e338 100644 --- a/message/tidy.go +++ b/message/tidy.go @@ -42,20 +42,17 @@ func tidy(argv0 *string) *string { // The field including one or more ";" for _, f := range strings.Split(bf, ";") { // 2-1. Trim leading and trailing space characters from the current buffer - f = strings.Trim(f, " ") - ps := "" + f = strings.Trim(f, " ") // 2-2. Convert some parameters to the lower-cased string - for { + ps := ""; for { // For example, // - Content-Type: Message/delivery-status => message/delivery-status // - Content-Type: Charset=UTF8 => charset=utf8 // - Reporting-MTA: DNS; ... => dns // - Final-Recipient: RFC822; ... => rfc822 if strings.IndexByte(f, ' ') > 0 { break } - - p2 := strings.IndexByte(f, '=') - if p2 > 0 { + if p2 := strings.IndexByte(f, '='); p2 > 0 { // charset=, boundary=, and other pairs divided by "=" ps = strings.ToLower(f[0:p2]) f = strings.Replace(f, f[0:p2], ps, 1) diff --git a/reason/find.go b/reason/find.go index 0bc57c4..038c6e0 100644 --- a/reason/find.go +++ b/reason/find.go @@ -57,12 +57,10 @@ func anotherone(fo *sis.Fact) string { trytomatch := false forsubject := "" - for trytomatch == false { + if trytomatch == false { // Set true when the reasontext is listed in GetRetried or fo.DiagnosticType is "SMTP" - if reasontext == "" { trytomatch = true; break } - if GetRetried[reasontext] { trytomatch = true; break } - if fo.DiagnosticType == "SMTP" { trytomatch = true; break } - break + if reasontext == "" || GetRetried[reasontext] { trytomatch = true } + if fo.DiagnosticType == "SMTP" { trytomatch = true } } if trytomatch == true { diff --git a/rfc1123/lib.go b/rfc1123/lib.go index 56d8375..c648f84 100644 --- a/rfc1123/lib.go +++ b/rfc1123/lib.go @@ -50,8 +50,7 @@ func IsInternetHost(argv1 string) bool { // @return bool true: is a valid Internet hostname // false: is not a valid Internet hostname // @see https://datatracker.ietf.org/doc/html/rfc1123 - if len(argv1) < 4 { return false } - if len(argv1) > 255 { return false } + if len(argv1) < 4 || len(argv1) > 255 { return false } // Deal "localhost", "localhost6" as a valid hostname if argv1 == "localhost" || argv1 == "localhost6" { return true } @@ -92,14 +91,11 @@ func IsDomainLiteral(email string) bool { if strings.Contains(email, "@[IPv4:") { // neko@[IPv4:192.0.2.25] - p1 := strings.Index(email, "@[IPv4:") - cv := email[p1 + 7:len(email) - 1] - return rfc791.IsIPv4Address(cv) + return rfc791.IsIPv4Address(sisimoji.Select(email, "@[IPv4:", "]", 0)) } else if strings.Contains(email, "@[IPv6:") { // neko@[IPv6:2001:0DB8:0000:0000:0000:0000:0000:0001] - p1 := strings.Index(email, "@[IPv6:") - cv := email[p1 + 7:len(email) - 1] + cv := sisimoji.Select(email, "@[IPv6:", "]", 0) if len(cv) == 39 && strings.Count(cv, ":") == 7 { return true } } return false @@ -164,9 +160,7 @@ func Find(argv1 string) string { for _, f := range Prefix0x32 { e = strings.ReplaceAll(e, f, "") } for _, f := range Suffix0x32 { e = strings.ReplaceAll(e, f, "") } - if len(e) < 4 { continue } - if strings.Contains(e, ".") == false { continue } - if IsInternetHost(e) == false { continue } + if len(e) < 4 || strings.Contains(e, ".") == false || IsInternetHost(e) == false { continue } foundtoken = append(foundtoken, e) } if len(foundtoken) == 0 { return "" } diff --git a/rfc1894/lib.go b/rfc1894/lib.go index 60fc5c4..f9e39af 100644 --- a/rfc1894/lib.go +++ b/rfc1894/lib.go @@ -148,8 +148,7 @@ func Field(argv0 string) []string { group, nyaan := fieldgroup[label] // "addr" if nyaan == false || len(captureson[group]) == 0 { return []string{} } - match := false - for _, e := range captureson[group] { + match := false; for _, e := range captureson[group] { // Try to match with each pattern of Per-Message field, Per-Recipient field if label == strings.ToLower(e) { match = true; break } } @@ -206,10 +205,8 @@ func Field(argv0 string) []string { if sisimoji.Aligned(table[2], []string{" (", ")"}) { // Extract text enclosed in parentheses as comments // Reporting-MTA: dns; mr21p30im-asmtp004.me.example.com (tcp-daemon) - p1 := strings.LastIndex(table[2], " (") - p2 := strings.LastIndex(table[2], ")" ) - table[4] = table[2][p1 + 2:p2] - table[2] = table[2][0:p1] + table[4] = sisimoji.Select(table[2], " (", ")", 0) + table[2] = table[2][0:strings.Index(table[2], " (")] } return table diff --git a/rfc2045/lib.go b/rfc2045/lib.go index 8d4b7ef..1338a74 100644 --- a/rfc2045/lib.go +++ b/rfc2045/lib.go @@ -28,8 +28,7 @@ func Parameter(argv0 string, argv1 string) string { // Find the value of the parameter name specified in "argv1" cf := strings.Split(argv0[ci + len(cv):], ";")[0]; if argv1 != "boundary" { cf = strings.ToLower(cf) } - cf = strings.Replace(cf, `'`, "", -1) - cf = strings.Replace(cf, `"`, "", -1) + for _, e := range []string{`'`, `"`} { cf = strings.Replace(cf, e, "", -1) } return cf } diff --git a/rfc2045/make-multipart-flat.go b/rfc2045/make-multipart-flat.go index 3451af1..670e205 100644 --- a/rfc2045/make-multipart-flat.go +++ b/rfc2045/make-multipart-flat.go @@ -36,14 +36,13 @@ func haircut(block *string, heads bool) []string { // Content-Type: text/plain; charset=us-ascii if strings.HasPrefix(e, "Content-Type:") { // Content-Type: *** - v := strings.SplitN(e, " ", 2) - if strings.Contains(v[1], "boundary=") { + if cv := strings.SplitN(e, " ", 2); strings.Contains(cv[1], "boundary=") { // Do not convert to lower-cased when the value of Content-Type include a boundary string - headerpart[0] = v[1] + headerpart[0] = cv[1] } else { // The value of Content-Type does not include a boundary string - headerpart[0] = strings.ToLower(v[1]) + headerpart[0] = strings.ToLower(cv[1]) } } else if strings.HasPrefix(e, "Content-Transfer-Encoding:") { // Content-Transfer-Encodig: *** @@ -61,6 +60,7 @@ func haircut(block *string, heads bool) []string { } if heads { return headerpart[:] } + mediatable := []string{"/rfc822", "/delivery-status", "/feedback-report"} mediatypev := strings.ToLower(headerpart[1]) ctencoding := headerpart[1] multipart1 := [...]string{headerpart[0], headerpart[1], ""} @@ -72,20 +72,14 @@ func haircut(block *string, heads bool) []string { // Do not append Content-Transfer-Encoding: header when the part is the original message: // Content-Type is message/rfc822 or text/rfc822-headers, or message/delivery-status, or // message/feedback-report - if strings.Contains(mediatypev, "/rfc822") { break } - if strings.Contains(mediatypev, "/delivery-status") { break } - if strings.Contains(mediatypev, "/feedback-report") { break } - if len(ctencoding) == 0 { break } - + if sisimoji.ContainsAny(mediatypev, mediatable) || ctencoding == "" { break } multipart1[2] += fmt.Sprintf("Content-Transfer-Encoding: %s\n", ctencoding) break } - for { - // LOWER CHUNK: Append LF before the lower chunk into the 2nd element of multipart1 - if lowerchunk == "" || lowerchunk[0:1] == "\n" { break } - multipart1[2] += "\n"; break - } + // LOWER CHUNK: Append LF before the lower chunk into the 2nd element of multipart1 + if lowerchunk != "" && lowerchunk[0:1] != "\n" { multipart1[2] += "\n" } + multipart1[2] += lowerchunk return multipart1[:] } @@ -113,52 +107,53 @@ func levelout(argv0 string, argv1 *string) ([][3]string, []sis.NotDecoded) { e = fmt.Sprintf("Content-Type: text/plain\n\n%s", e) } - if f := haircut(&e, false); strings.Contains(f[0], "multipart/") { + if cf := haircut(&e, false); strings.Contains(cf[0], "multipart/") { // There is nested multipart/* block - boundary02 := Boundary(f[0], -1); if len(boundary02) == 0 { continue } - bodyinside := strings.SplitN(f[2], "\n\n", 2)[1] + boundary02 := Boundary(cf[0], -1); if len(boundary02) == 0 { continue } + bodyinside := strings.SplitN(cf[2], "\n\n", 2)[1] if len(bodyinside) < 8 || strings.Contains(bodyinside, boundary02) == false { continue } - v, ce := levelout(f[0], &bodyinside) + cv, ce := levelout(cf[0], &bodyinside) if ce != nil && len(ce) > 0 { // There is any errors notdecoded = append(notdecoded, ce...) - if v == nil { continue } + if cv == nil { continue } } - for _, w := range v { partstable = append(partstable, [3]string{w[0], w[1], w[2]}) } + for _, w := range cv { partstable = append(partstable, [3]string{w[0], w[1], w[2]}) } } else { // The part is not a multipart/* block - b := e; if len(f[len(f) - 1]) > 0 { b = f[len(f) - 1] } - c := Parameter(f[0], "charset") + cw := len(cf) + ub := e; if len(cf[cw - 1]) > 0 { ub = cf[cw - 1] } - if sisimoji.Is8Bit(&b) { + if sisimoji.Is8Bit(&ub) { // Avoid the following errors in DecodeQ() // - quotedprintable: invalid unescaped byte 0x1b in body - utf8string, nyaan := sisimoji.ToUTF8([]byte(b), c); if nyaan != nil { + cz := Parameter(cf[0], "charset") + utf8string, nyaan := sisimoji.ToUTF8([]byte(ub), cz); if nyaan != nil { // Failed to convert the string to UTF-8 ce := *sis.MakeNotDecoded(fmt.Sprintf("%s", nyaan), false) notdecoded = append(notdecoded, ce) } - if utf8string != "" { b = utf8string } + if utf8string != "" { ub = utf8string } } - v := [3]string{f[0], f[1], b} - for len(f[0]) > 0 { - if f[0] == "" || b == "" || strings.Contains(b, "\n\n") == false { break } - v[2] = strings.SplitN(b, "\n\n", 2)[1] + cv := [3]string{cf[0], cf[1], ub}; for len(cf[0]) > 0 { + if cf[0] == "" || ub == "" || strings.Contains(ub, "\n\n") == false { break } + cv[2] = strings.SplitN(ub, "\n\n", 2)[1] break } - partstable = append(partstable, v) + partstable = append(partstable, cv) } } if len(partstable) == 0 { return nil, notdecoded } // Remove `boundary01 + '--'` and strings from the boundary to the end of the body part. boundary01 = strings.Replace(boundary01, "\n", "", -1) - b := partstable[len(partstable) - 1][2] - p := strings.Index(b, boundary01 + "--") - if p > -1 { partstable[len(partstable) - 1][2] = strings.SplitN(b, boundary01 + "--", 2)[0] } + cw := len(partstable) + bo := partstable[cw - 1][2] + p1 := strings.Index(bo, boundary01 + "--") + if p1 > -1 { partstable[cw - 1][2] = strings.SplitN(bo, boundary01 + "--", 2)[0] } return partstable, notdecoded } @@ -195,6 +190,7 @@ func MakeFlat(argv0 string, argv1 *string) (*string, []sis.NotDecoded) { *argv1 = strings.Replace(*argv1, e + "=", strings.ToLower(e) + "=", -1) } *argv1 = strings.Replace(*argv1, "message/xdelivery-status", "message/delivery-status", -1) + multiparts, notdecoded := levelout(argv0, argv1) flattenout := "" delimiters := []string{"/delivery-status", "/rfc822", "/feedback-report", "/partial"} @@ -214,11 +210,10 @@ func MakeFlat(argv0 string, argv1 *string) (*string, []sis.NotDecoded) { if strings.Contains(lhead, "multipart/alternative") { continue } istexthtml = true } - ctencoding := e[1] // The value of Content-Transfer-Encoding header bodyinside := e[2] // Message body of the part bodystring := "" - if len(ctencoding) > 0 { + if ctencoding := e[1]; len(ctencoding) > 0 { // Check the value of Content-Transfer-Encoding: header if ctencoding == "base64" { // Content-Transfer-Encoding: base64 diff --git a/rfc2045/mime-decode.go b/rfc2045/mime-decode.go index 0b5a547..8fa29bb 100644 --- a/rfc2045/mime-decode.go +++ b/rfc2045/mime-decode.go @@ -20,25 +20,21 @@ func IsEncoded(argv0 string) bool { // @return bool true: Not MIME encoded string // false: MIME encoded string argv0 = strings.ToUpper(argv0) - match := false - for { - // =?UTF-8?B?44OL44Oj44O844Oz?= - if !strings.Contains(argv0, "=?") { break } // Begins with "=?" - if !strings.Contains(argv0, "?=") { break } // Ends with "?=" - if len(argv0) < 8 { break } // String length should be 8 or more - if strings.Contains(argv0, "?B?") || strings.Contains(argv0, "?Q?") { match = true } - break - } - return match + + // =?UTF-8?B?44OL44Oj44O844Oz?= + if strings.Contains(argv0, "=?") == false { return false } // Should begin with "=?" + if strings.Contains(argv0, "?=") == false { return false } // Should end with "?=" + if len(argv0) < 8 { return false } // Should be 8 or more length + if strings.Contains(argv0, "?B?") || strings.Contains(argv0, "?Q?") { return true } + return false } // DecodeH() decodes the value of email header which is a MIME-Encoded string. func DecodeH(argv0 string) (string, error) { // @param string argvs MIME-Encoded text // @return string MIME-Decoded text - toreadable := "" // Human readble text (has decoded) - stringlist := []string{} - replacingc := []string{".", "[", "]"} + if argv0 == "" { return "", nil } + decodingif := new(mime.WordDecoder); if CharacterSet(argv0) != "UTF-8" { // The character set is not UTF-8 decodingif.CharsetReader = func(c string, v io.Reader) (io.Reader, error) { @@ -47,6 +43,10 @@ func DecodeH(argv0 string) (string, error) { } } + toreadable := "" // Human readble text (has decoded) + stringlist := []string{} + replacingc := []string{".", "[", "]"} + if strings.Contains(argv0, " ") { // The argument string include 1 or more space characters stringlist = strings.Split(argv0, " ") @@ -75,9 +75,9 @@ func DecodeH(argv0 string) (string, error) { for _, c := range replacingc { e = strings.Replace(e, "?=" + c, "?=", -1) } } - if f, nyaan := decodingif.DecodeHeader(e); nyaan == nil { + if cv, nyaan := decodingif.DecodeHeader(e); nyaan == nil { // Successfully decoded - if j > 0 { toreadable += " " }; toreadable += f + if j > 0 { toreadable += " " }; toreadable += cv } else { // Failed to decode @@ -96,8 +96,7 @@ func DecodeB(argv0 string, argv1 string) (string, error) { if len(argv1) == 0 { argv1 = "utf-8" } decodingif := new(mime.WordDecoder) - base64text := strings.TrimSpace(argv0) - base64text = strings.Join(strings.Split(base64text, "\n"), "") + base64text := strings.Join(strings.Split(strings.TrimSpace(argv0), "\n"), "") base64text = fmt.Sprintf("=?%s?B?%s?=", argv1, base64text) plainvalue := "" diff --git a/rfc3464/lib.go b/rfc3464/lib.go index cf06150..21a5e71 100644 --- a/rfc3464/lib.go +++ b/rfc3464/lib.go @@ -145,8 +145,7 @@ func Inquire(bf *sis.BeforeFact) sis.RisingUnderway { } continue } - if readcursor & indicators["deliverystatus"] == 0 { continue } - if e == "" { continue } + if readcursor & indicators["deliverystatus"] == 0 || e == "" { continue } if f := rfc1894.Match(e); f > 0 { // This line matched with any field defined in RFC3464 diff --git a/rfc3834/lib.go b/rfc3834/lib.go index 4e14deb..e61bc0e 100644 --- a/rfc3834/lib.go +++ b/rfc3834/lib.go @@ -88,8 +88,7 @@ func Inquire(bf *sis.BeforeFact) sis.RisingUnderway { if bf.Headers["content-type"][0] != "" { // Get the boundary string and set regular expression for matching with the boundary string. - cv := rfc2045.Boundary(bf.Headers["content-type"][0], 0) - if cv != "" { boundaries[0] = cv } + if cv := rfc2045.Boundary(bf.Headers["content-type"][0], 0); cv != "" { boundaries[0] = cv } } if len(bodyslices) < 5 { diff --git a/rfc5322/address.go b/rfc5322/address.go index 8416bf1..260c693 100644 --- a/rfc5322/address.go +++ b/rfc5322/address.go @@ -44,8 +44,7 @@ func IsEmailAddress(email string) bool { quote := IsQuotedAddress(email); if quote == false { // The email address is not a quoted address - if strings.Count(email, "@") > 1 { return false } - if strings.Contains(email, " ") { return false } + if strings.Count(email, "@") > 1 || strings.Contains(email, " ") { return false } // Non-RFC compliant email addresses still persist in the world. // if strings.Contains(email, "..") { return false } @@ -120,8 +119,7 @@ func IsQuotedAddress(email string) bool { // @param string email Email address string // @return bool true: the local part is quoted // false: the local part is not quoted - if strings.HasPrefix(email, `"`) == false { return false } - if strings.Contains(email, `"@`) == false { return false } + if strings.HasPrefix(email, `"`) == false || strings.Contains(email, `"@`) == false { return false } return true } diff --git a/rfc5322/received.go b/rfc5322/received.go index 947cff3..0e4c756 100644 --- a/rfc5322/received.go +++ b/rfc5322/received.go @@ -41,28 +41,26 @@ func Received(argv1 string) [6]string { recvd := strings.Split(argv1, " ") label := [6]string{"from", "by", "via", "with", "id", "for"} skips := []string{"unknown", "localhost", "[127.0.0.1]", "[IPv6:::1]"} + chars := []string{"(", ")", ";"} // Removed by strings.ReplaceAll() token := make(map[string]string) other := []string{} alter := []string{} right := false - for i, e := range recvd { + for j, e := range recvd { // Look up each label defined in label from Received header - f := strings.ToLower(e) - p := false - for _, v := range label { if f == v { p = true; break } } + cf := strings.ToLower(e) + cb := false - if p == false { continue } - if i + 1 > len(recvd) - 1 { continue } + for _, v := range label { if cf == v { cb = true; break } } + if cb == false || j + 1 > len(recvd) - 1 { continue } - token[f] = strings.ToLower(recvd[i + 1]); - token[f] = strings.ReplaceAll(token[f], "(", "") - token[f] = strings.ReplaceAll(token[f], ")", "") - token[f] = strings.ReplaceAll(token[f], ";", "") + token[cf] = strings.ToLower(recvd[j + 1]); + for _, f := range chars { token[cf] = strings.ReplaceAll(token[cf], f, "") } - if f != "from" { continue } - if i + 2 > len(recvd) - 1 { break } - if strings.Index(recvd[i + 2], "(") != 0 { continue } + if cf != "from" { continue } + if j + 2 > len(recvd) - 1 { break } + if strings.Index(recvd[j + 2], "(") != 0 { continue } // Get and keep a hostname in the comment as follows: // from mx1.example.com (c213502.kyoto.example.ne.jp [192.0.2.135]) by mx.example.jp (V8/cf) @@ -78,18 +76,14 @@ func Received(argv1 string) [6]string { // } // The 2nd element after the current element is NOT a continuation of the current element // such as "(c213502.kyoto.example.ne.jp)" - other = append(other, recvd[i + 2]) - other[0] = strings.ReplaceAll(other[0], "(", "") - other[0] = strings.ReplaceAll(other[0], ")", "") - other[0] = strings.ReplaceAll(other[0], ";", "") + other = append(other, recvd[j + 2]) + for _, f := range chars { other[0] = strings.ReplaceAll(other[0], f, "") } // The 2nd element after the current element is a continuation of the current element. // such as "(c213502.kyoto.example.ne.jp", "[192.0.2.135])" - if i + 3 > len(recvd) - 1 { break } - other = append(other, recvd[i + 3]) - other[1] = strings.ReplaceAll(other[1], "(", "") - other[1] = strings.ReplaceAll(other[1], ")", "") - other[1] = strings.ReplaceAll(other[1], ";", "") + if j + 3 > len(recvd) - 1 { break } + other = append(other, recvd[j + 3]) + for _, f := range chars { other[1] = strings.ReplaceAll(other[1], f, "") } } for _, e := range other { @@ -115,9 +109,7 @@ func Received(argv1 string) [6]string { if token["from"] == "localhost" { break } if token["from"] == "localhost.localdomain" { break } if strings.Index(token["from"], ".") < 0 { break } // A hostname without a domain name - - ce := token["from"]; - if len(rfc791.FindIPv4Address(&ce)) > 0 { break } + if ce := token["from"]; len(rfc791.FindIPv4Address(&ce)) > 0 { break } // No need to rewrite token["from"] right = true diff --git a/rfc791/lib.go b/rfc791/lib.go index 6947f2b..007a260 100644 --- a/rfc791/lib.go +++ b/rfc791/lib.go @@ -38,9 +38,8 @@ func FindIPv4Address(argv1 *string) []string { // Rewrite: "mx.example.jp[192.0.2.1]" => "mx.example.jp 192.0.2.1" argv2 := *argv1 for _, e := range []string{"(", ")", "[", "]", ","} { argv2 = strings.ReplaceAll(argv2, e, " ") } - ipv4a := []string{} - for _, e := range strings.Split(argv2, " ") { + ipv4a := []string{}; for _, e := range strings.Split(argv2, " ") { // Find a string including an IPv4 address if !strings.Contains(e, ".") { continue } // IPv4 address must include "." character if !IsIPv4Address(e) { continue } // The string is an IPv4 address or not diff --git a/rhost/for-cox.go b/rhost/for-cox.go index ed6696c..42a3b08 100644 --- a/rhost/for-cox.go +++ b/rhost/for-cox.go @@ -138,13 +138,7 @@ func init() { } issuedcode := fo.DiagnosticCode + " " - codenumber := "" - for { - p0 := strings.Index(issuedcode, "AUP#"); if p0 < 0 { break } - p1 := strings.Index(issuedcode[p0:], " "); if p1 < 0 { break } - codenumber = issuedcode[p0 + 4:p0 + p1] - break - } + codenumber := sisimoji.Select(issuedcode, "AUP#", " ", 0) reasontext := errorcodes[codenumber] if reasontext == "" { diff --git a/rhost/for-godaddy.go b/rhost/for-godaddy.go index 8ec2675..86653f8 100644 --- a/rhost/for-godaddy.go +++ b/rhost/for-godaddy.go @@ -216,11 +216,10 @@ func init() { } issuedcode := fo.DiagnosticCode - positionib := strings.Index(issuedcode, " IB") - if positionib > 1 { + errorlabel := "IB" + sisimoji.Select(issuedcode, " IB", " ", 0) + if errorcodes[errorlabel] != "" { // 192.0.2.22 has sent to too many recipients this hour. IB607 ... - errorlabel := issuedcode[positionib + 1:positionib + 6] - if errorcodes[errorlabel] != "" { return errorcodes[errorlabel] } + return errorcodes[errorlabel] } else { // There is no " IB***" error code in the error message diff --git a/rhost/for-iua.go b/rhost/for-iua.go index 2f35e50..6d85f53 100644 --- a/rhost/for-iua.go +++ b/rhost/for-iua.go @@ -9,6 +9,7 @@ package rhost import "strings" import "libsisimai.org/sisimai/sis" +import sisimoji "libsisimai.org/sisimai/string" func init() { // Detect the reason of the bounce returned by this email service @@ -32,13 +33,7 @@ func init() { "10": "filtered", // Not in the list Mail address management. } issuedcode := strings.ToLower(fo.DiagnosticCode) - partofaddr := ".i.ua/err/" - if strings.Contains(issuedcode, partofaddr) == false { return "" } - - errorindex := strings.Index(issuedcode, partofaddr) - codenumber := issuedcode[errorindex + len(partofaddr):errorindex + len(partofaddr) + 1] - if strings.HasSuffix(codenumber, "/") { codenumber = strings.TrimRight(codenumber, "/") } - + codenumber := sisimoji.Select(issuedcode, ".i.ua/err/", "/", 0); if codenumber == "" { return "" } return errorcodes[codenumber] } } diff --git a/smtp/reply/lib.go b/smtp/reply/lib.go index a5ec3f0..e5eabf5 100644 --- a/smtp/reply/lib.go +++ b/smtp/reply/lib.go @@ -102,8 +102,7 @@ func Test(argv0 string) bool { if reply > 557 { return false } // The maximum SMTP Reply code is 557 first := reply % 100 - if first > 59 { return false } // For example, 499 is not an SMTP Reply code - + if first > 59 { return false } // For example, 499 is not an SMTP Reply code if first == 2 { // 2yz if reply == 235 { return true } // 235 is a valid code for AUTH (RFC4954) @@ -111,12 +110,8 @@ func Test(argv0 string) bool { if reply > 221 && reply < 250 { return false } // There is no reply code between 221 and 250 return true } + if first == 3 && reply != 354 { return false } - if first == 3 { - // 3yz - if reply != 354 { return false } - return true - } return true } diff --git a/smtp/status/test.go b/smtp/status/test.go index b28fd60..bec2301 100644 --- a/smtp/status/test.go +++ b/smtp/status/test.go @@ -22,14 +22,10 @@ func Test(argv1 string) bool { digit, nyaan := strconv.Atoi(e); if nyaan != nil { break } token = append(token, int16(digit)) } - if len(token) != 3 { return false } // The number of elements should be 3 like [5,1,1] - if token[0] < 2 { return false } // Status: 1.x.y does not exist - if token[0] == 3 { return false } // Status: 3.x.y does not exist - if token[0] > 5 { return false } // Status: 6.x.y does not exist - if token[1] < 0 { return false } - if token[1] > 7 { return false } - if token[2] < 0 { return false } + + if token[0] < 2 || token[0] == 3 || token[0] > 5 { return false } // Status: [136].y.z does not exist + if token[1] < 0 || token[1] > 7 || token[2] < 0 { return false } return true } diff --git a/smtp/transcript/lib.go b/smtp/transcript/lib.go index d59d160..9fbbe08 100644 --- a/smtp/transcript/lib.go +++ b/smtp/transcript/lib.go @@ -159,9 +159,8 @@ func Rise(argv0, argv1, argv2 string) []TranscriptLog { for _, f := range strings.Split(parameters, " ") { // SIZE=22022, PROTO=SMTP, and so on - if strings.IndexByte(f, '=') < 1 { continue } - if len(f) < 3 { continue } - ee := strings.Split(f, "="); if len(ee) != 2 { continue } + if strings.IndexByte(f, '=') < 1 || len(f) < 3 { continue } + ee := strings.Split(f, "="); if len(ee) != 2 { continue } cursession.Parameter[strings.ToLower(ee[0])] = ee[1] } } diff --git a/string/14-select_test.go b/string/14-select_test.go new file mode 100644 index 0000000..87ae43e --- /dev/null +++ b/string/14-select_test.go @@ -0,0 +1,35 @@ +// Copyright (C) 2025 azumakuniyuki and sisimai development team, All rights reserved. +// This software is distributed under The BSD 2-Clause License. +package string + +// _____ _ __ _ _ +// |_ _|__ ___| |_ / /__| |_ _ __(_)_ __ __ _ +// | |/ _ \/ __| __| / / __| __| '__| | '_ \ / _` | +// | | __/\__ \ |_ / /\__ \ |_| | | | | | | (_| | +// |_|\___||___/\__/_/ |___/\__|_| |_|_| |_|\__, | +// |___/ +import "testing" + +func TestSelect(t *testing.T) { + fn := "sisimai/string.Select" + cx := 0 + ae := []struct {arg string; b string; u string; s int; exp string}{ + {"From: Kijitora", "<", ">", 0, "neko@example.jp"}, + {"Diagnostic-Code: smtp;550 5.1.1 ... User Unknown", " ", ";", 4, "smtp"}, + {"From: \nTo: \n ", "\nTo: ", "\n", 0, ""}, + {"Status: 4.4.0 (undefined routing status)", " (", ")", 1, "undefined routing status"}, + {"550-5.7.26 The MAIL FROM domain [email.example.jp] has an SPF", " [", "] ", 10, "email.example.jp"}, + } + + for _, e := range ae { + cx++; if cv := Select(e.arg, e.b, e.u, e.s); cv != e.exp { + t.Errorf("%s(%s..., %s, %s, %d) returns [%s]", fn, e.arg[e.s:e.s + 10], e.b, e.u, e.s, cv) + } + cx++; if cv := Select(e.arg, e.b, e.u, e.s * 10 + 50); cv == e.exp { + t.Errorf("%s(%s..., %s, %s, %d) returns [%s]", fn, e.arg[e.s:e.s + 10], e.b, e.u, e.s, e.exp) + } + } + + t.Logf("The number of tests = %d", cx) +} + diff --git a/string/lib.go b/string/lib.go index 1ebae8e..a450c43 100644 --- a/string/lib.go +++ b/string/lib.go @@ -58,14 +58,10 @@ func Sweep(argv1 string) string { // @return string Cleaned out string if argv1 == "" { return "" } - argv1 = strings.ReplaceAll(argv1, "\t", " ") - argv1 = strings.TrimSpace(argv1) - argv1 = Squeeze(argv1, " ") - + argv1 = Squeeze(strings.TrimSpace(strings.ReplaceAll(argv1, "\t", " ")), " ") for strings.Contains(argv1, " --") { // Delete all the string after a boundary string like " --neko-chan" if strings.Contains(argv1, "-- ") { break } - if strings.Contains(argv1, "--\t") { break } argv1 = argv1[0:strings.Index(argv1, " --")] } return argv1 @@ -115,3 +111,30 @@ func IndexOnTheWay(argv0, argv1 string, start int) int { return fi + start } +// Select() returns a string selected between the 2nd argument and 3rd argument from the 1st argument +func Select(argv0, begin, until string, start int) string { + // @param string argv0 The string to be searched for example "From: " + // @param string begin Substring such as "<" + // @param string until Substring such as ">" + // @param int start The index position for seeking + // @return string selected string such as "neko@example.jp" + if argv0 == "" || begin == "" || until == "" || start < 0 { return "" } + + textlength := [3]int{len(argv0), len(begin), len(until)} + sourcetext := argv0 + + if start > 0 { + if start > textlength[0] - 2 { return "" } + sourcetext = argv0[start:] + textlength[0] = len(sourcetext) + } + + if textlength[0] < 3 || textlength[0] <= (textlength[1] + textlength[2]) { return "" } + indextable := [3]int{0, -1, -1} + indextable[1] = strings.Index(sourcetext, begin); if indextable[1] == -1 { return "" } + indextable[2] = strings.Index(sourcetext[indextable[1] + textlength[1] + 1:], until) + + if indextable[2] < 0 { return "" }; indextable[2] += indextable[1] + textlength[1] + 1 + return sourcetext[indextable[1] + textlength[1]:indextable[2]] +} + diff --git a/string/to-something.go b/string/to-something.go index 1cd0075..5a94711 100644 --- a/string/to-something.go +++ b/string/to-something.go @@ -18,9 +18,7 @@ func ToLF(argv0 *string) *string { // @return *string LF converted text if argv0 == nil || *argv0 == "" { return argv0 } - characters := [2]string{"\r\n", "\r"} - crreplaced := *argv0 - for _, e := range characters { + crreplaced := *argv0; for _, e := range [2]string{"\r\n", "\r"} { // Convert CRLF and CR to LF if strings.Contains(crreplaced, e) == false { continue } crreplaced = strings.ReplaceAll(crreplaced, e, "\n")