about summary refs log tree commit diff stats
path: root/lib/format
diff options
context:
space:
mode:
authorReto Brunner <reto@labrat.space>2020-08-19 12:01:45 +0200
committerReto Brunner <reto@labrat.space>2020-08-20 19:18:57 +0200
commitc84630714405a1e93766a6a6c023801302a3ea66 (patch)
tree156e9f45c6847a123f677594c8aff3a82322bce8 /lib/format
parentfe1cabb077cf6c6cb3de122b3f5532acbeba8c85 (diff)
downloadaerc-c84630714405a1e93766a6a6c023801302a3ea66.tar.gz
base models.Address on the mail.Address type
This allows us to hook into the std libs implementation of parsing related stuff.
For this, we need to get rid of the distinction between a mailbox and a host
to just a single "address" field.

However this is already the common case. All but one users immediately
concatenated the mbox/domain to a single address.

So this in effects makes it simpler for most cases and we simply do the
transformation in the special case.
Diffstat (limited to 'lib/format')
-rw-r--r--lib/format/format.go60
1 files changed, 44 insertions, 16 deletions
diff --git a/lib/format/format.go b/lib/format/format.go
index cc46da8..06b4d3f 100644
--- a/lib/format/format.go
+++ b/lib/format/format.go
@@ -2,22 +2,46 @@ package format
 
 import (
 	"errors"
-	"fmt"
+	"mime"
 	gomail "net/mail"
 	"strings"
 	"time"
 	"unicode"
 
 	"git.sr.ht/~sircmpwn/aerc/models"
+	"github.com/emersion/go-message"
 )
 
-func parseAddress(address string) *gomail.Address {
+func ParseAddress(address string) (*models.Address, error) {
 	addrs, err := gomail.ParseAddress(address)
 	if err != nil {
-		return nil
+		return nil, err
+	}
+	return (*models.Address)(addrs), nil
+}
+
+func ParseAddressList(s string) ([]*models.Address, error) {
+	parser := gomail.AddressParser{
+		&mime.WordDecoder{message.CharsetReader},
+	}
+	list, err := parser.ParseList(s)
+	if err != nil {
+		return nil, err
 	}
 
-	return addrs
+	addrs := make([]*models.Address, len(list))
+	for i, a := range list {
+		addrs[i] = (*models.Address)(a)
+	}
+	return addrs, nil
+}
+
+func FormatAddresses(l []*models.Address) string {
+	formatted := make([]string, len(l))
+	for i, a := range l {
+		formatted[i] = a.Format()
+	}
+	return strings.Join(formatted, ", ")
 }
 
 func ParseMessageFormat(
@@ -29,7 +53,10 @@ func ParseMessageFormat(
 	retval := make([]byte, 0, len(format))
 	var args []interface{}
 
-	accountFromAddress := parseAddress(fromAddress)
+	accountFromAddress, err := ParseAddress(fromAddress)
+	if err != nil {
+		return "", nil, err
+	}
 
 	var c rune
 	for i, ni := 0, 0; i < len(format); {
@@ -87,8 +114,7 @@ func ParseMessageFormat(
 			}
 			addr := msg.Envelope.From[0]
 			retval = append(retval, 's')
-			args = append(args,
-				fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host))
+			args = append(args, addr.Address)
 		case 'A':
 			if msg.Envelope == nil {
 				return "", nil,
@@ -106,8 +132,7 @@ func ParseMessageFormat(
 				addr = msg.Envelope.ReplyTo[0]
 			}
 			retval = append(retval, 's')
-			args = append(args,
-				fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host))
+			args = append(args, addr.Address)
 		case 'C':
 			retval = append(retval, 'd')
 			args = append(args, number)
@@ -158,7 +183,7 @@ func ParseMessageFormat(
 			if addr.Name != "" {
 				val = addr.Name
 			} else {
-				val = fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host)
+				val = addr.Address
 			}
 			retval = append(retval, 's')
 			args = append(args, val)
@@ -188,7 +213,7 @@ func ParseMessageFormat(
 			if addr.Name != "" {
 				val = addr.Name
 			} else {
-				val = fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host)
+				val = addr.Address
 			}
 			retval = append(retval, 's')
 			args = append(args, val)
@@ -197,7 +222,7 @@ func ParseMessageFormat(
 				return "", nil,
 					errors.New("no envelope available for this message")
 			}
-			addrs := models.FormatAddresses(msg.Envelope.To)
+			addrs := FormatAddresses(msg.Envelope.To)
 			retval = append(retval, 's')
 			args = append(args, addrs)
 		case 'R':
@@ -205,7 +230,7 @@ func ParseMessageFormat(
 				return "", nil,
 					errors.New("no envelope available for this message")
 			}
-			addrs := models.FormatAddresses(msg.Envelope.Cc)
+			addrs := FormatAddresses(msg.Envelope.Cc)
 			retval = append(retval, 's')
 			args = append(args, addrs)
 		case 's':
@@ -226,8 +251,7 @@ func ParseMessageFormat(
 			}
 			addr := msg.Envelope.To[0]
 			retval = append(retval, 's')
-			args = append(args,
-				fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host))
+			args = append(args, addr.Address)
 		case 'T':
 			retval = append(retval, 's')
 			args = append(args, accountName)
@@ -241,8 +265,12 @@ func ParseMessageFormat(
 					errors.New("found no address for sender")
 			}
 			addr := msg.Envelope.From[0]
+			mailbox := addr.Address // fallback if there's no @ sign
+			if split := strings.SplitN(addr.Address, "@", 2); len(split) == 2 {
+				mailbox = split[1]
+			}
 			retval = append(retval, 's')
-			args = append(args, addr.Mailbox)
+			args = append(args, mailbox)
 		case 'v':
 			if msg.Envelope == nil {
 				return "", nil,
an class="na">type="text/css"> <!-- pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffd7; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #ffffd7; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } .PreProc { color: #c000c0; } .Special { color: #ff6060; } .LineNr { } .muRegEsi { color: #005faf; } .Constant { color: #008787; } .muRegEdi { color: #00af00; } .Delimiter { color: #c000c0; } .muFunction { color: #af5f00; text-decoration: underline; } .muComment { color: #005faf; } --> </style> <script type='text/javascript'> <!-- /* function to open any folds containing a jumped-to line before jumping to it */ function JumpToLine() { var lineNum; lineNum = window.location.hash; lineNum = lineNum.substr(1); /* strip off '#' */ if (lineNum.indexOf('L') == -1) { lineNum = 'L'+lineNum; } var lineElem = document.getElementById(lineNum); /* Always jump to new location even if the line was hidden inside a fold, or * we corrected the raw number to a line ID. */ if (lineElem) { lineElem.scrollIntoView(true); } return true; } if ('onhashchange' in window) { window.onhashchange = JumpToLine; } --> </script> </head> <body onload='JumpToLine();'> <a href='https://github.com/akkartik/mu/blob/main/apps/ex9.mu'>https://github.com/akkartik/mu/blob/main/apps/ex9.mu</a> <pre id='vimCodeElement'> <span id="L1" class="LineNr"> 1 </span><span class="muComment"># Demo of reading and writing to disk.</span> <span id="L2" class="LineNr"> 2 </span><span class="muComment">#</span> <span id="L3" class="LineNr"> 3 </span><span class="muComment"># Steps for trying it out:</span> <span id="L4" class="LineNr"> 4 </span><span class="muComment"># 1. Translate this example into a disk image code.img.</span> <span id="L5" class="LineNr"> 5 </span><span class="muComment"># ./translate apps/ex9.mu</span> <span id="L6" class="LineNr"> 6 </span><span class="muComment"># 2. Build a second disk image data.img containing some text.</span> <span id="L7" class="LineNr"> 7 </span><span class="muComment"># dd if=/dev/zero of=data.img count=20160</span> <span id="L8" class="LineNr"> 8 </span><span class="muComment"># echo 'abc def ghi' |dd of=data.img conv=notrunc</span> <span id="L9" class="LineNr"> 9 </span><span class="muComment"># 3. Familiarize yourself with how the data disk looks within xxd:</span> <span id="L10" class="LineNr">10 </span><span class="muComment"># xxd data.img |head</span> <span id="L11" class="LineNr">11 </span><span class="muComment"># 4. Run in an emulator, either Qemu or Bochs.</span> <span id="L12" class="LineNr">12 </span><span class="muComment"># qemu-system-i386 -hda code.img -hdb data.img</span> <span id="L13" class="LineNr">13 </span><span class="muComment"># bochs -f bochsrc.2disks</span> <span id="L14" class="LineNr">14 </span><span class="muComment"># 5. Exit the emulator.</span> <span id="L15" class="LineNr">15 </span><span class="muComment"># 6. Notice that the data disk now contains the word count of the original text.</span> <span id="L16" class="LineNr">16 </span><span class="muComment"># xxd data.img |head</span> <span id="L17" class="LineNr">17 </span> <span id="L18" class="LineNr">18 </span><span class="PreProc">fn</span> <span class="muFunction"><a href='ex9.mu.html#L18'>main</a></span> <a href='../500fake-screen.mu.html#L14'>screen</a>: (addr <a href='../500fake-screen.mu.html#L14'>screen</a>), keyboard: (addr keyboard), data-disk: (addr disk) <span class="Delimiter">{</span> <span id="L19" class="LineNr">19 </span> <span class="PreProc">var</span> text-storage: (stream byte <span class="Constant">0x200</span>) <span id="L20" class="LineNr">20 </span> <span class="PreProc">var</span> text/<span class="muRegEsi">esi</span>: (addr stream byte) <span class="Special">&lt;-</span> address text-storage <span id="L21" class="LineNr">21 </span> <a href='../510disk.mu.html#L1'>load-sectors</a> data-disk, <span class="Constant">0</span>/lba, <span class="Constant">1</span>/num-sectors, text <span id="L22" class="LineNr">22 </span> <span id="L23" class="LineNr">23 </span> <span class="PreProc">var</span> <a href='ex9.mu.html#L31'>word-count</a>/eax: int <span class="Special">&lt;-</span> <a href='ex9.mu.html#L31'>word-count</a> text <span id="L24" class="LineNr">24 </span> <span id="L25" class="LineNr">25 </span> <span class="PreProc">var</span> result-storage: (stream byte <span class="Constant">0x10</span>) <span id="L26" class="LineNr">26 </span> <span class="PreProc">var</span> result/<span class="muRegEdi">edi</span>: (addr stream byte) <span class="Special">&lt;-</span> address result-storage <span id="L27" class="LineNr">27 </span> <a href='../126write-int-decimal.subx.html#L8'>write-int32-decimal</a> result, <a href='ex9.mu.html#L31'>word-count</a> <span id="L28" class="LineNr">28 </span> <a href='../510disk.mu.html#L23'>store-sectors</a> data-disk, <span class="Constant">0</span>/lba, <span class="Constant">1</span>/num-sectors, result <span id="L29" class="LineNr">29 </span><span class="Delimiter">}</span> <span id="L30" class="LineNr">30 </span> <span id="L31" class="LineNr">31 </span><span class="PreProc">fn</span> <span class="muFunction"><a href='ex9.mu.html#L31'>word-count</a></span> in: (addr stream byte)<span class="PreProc"> -&gt; </span>_/eax: int <span class="Delimiter">{</span> <span id="L32" class="LineNr">32 </span> <span class="PreProc">var</span> result/<span class="muRegEdi">edi</span>: int <span class="Special">&lt;-</span> copy <span class="Constant">0</span> <span id="L33" class="LineNr">33 </span> <span class="Delimiter">{</span> <span id="L34" class="LineNr">34 </span> <span class="PreProc">var</span> done?/eax: boolean <span class="Special">&lt;-</span> <a href='../309stream.subx.html#L6'>stream-empty?</a> in <span id="L35" class="LineNr">35 </span> compare done?, <span class="Constant">0</span>/false <span id="L36" class="LineNr">36 </span> <span class="PreProc">break-if-!=</span> <span id="L37" class="LineNr">37 </span> <span class="PreProc">var</span> g/eax: grapheme <span class="Special">&lt;-</span> <a href='../403unicode.mu.html#L92'>read-grapheme</a> in <span id="L38" class="LineNr">38 </span> <span class="Delimiter">{</span> <span id="L39" class="LineNr">39 </span> compare g, <span class="Constant">0x20</span>/space <span id="L40" class="LineNr">40 </span> <span class="PreProc">break-if-!=</span> <span id="L41" class="LineNr">41 </span> result <span class="Special">&lt;-</span> increment <span id="L42" class="LineNr">42 </span> <span class="Delimiter">}</span> <span id="L43" class="LineNr">43 </span> <span class="Delimiter">{</span> <span id="L44" class="LineNr">44 </span> compare g, <span class="Constant">0xa</span>/newline <span id="L45" class="LineNr">45 </span> <span class="PreProc">break-if-!=</span> <span id="L46" class="LineNr">46 </span> result <span class="Special">&lt;-</span> increment <span id="L47" class="LineNr">47 </span> <span class="Delimiter">}</span> <span id="L48" class="LineNr">48 </span> <span class="PreProc">loop</span> <span id="L49" class="LineNr">49 </span> <span class="Delimiter">}</span> <span id="L50" class="LineNr">50 </span> <span class="PreProc">return</span> result <span id="L51" class="LineNr">51 </span><span class="Delimiter">}</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->