1

I'm working on Emacs 29.1 at MacOs BigSur

I have a mu4e smtp account setup in ~/.authinfo

machine server1 login mail_users password pass1 port 587
machine server1 login user_admin password pass2 port 587
machine server2 login login2 password pass3 port 587
machine server3 login login3 password pass4 port 587

When I use server1 and server2 send mails works. When I'm adding the fourth entry server3 I get the strange message

Unexpected ‘machine’ token at line 4

OK line 4 has a classical structure and obviously machine token is correct one to put it at the beginning of the line.

For all 4 machine entries corresponding configurations for thunderbird working.

Question 1: What causes that error because despite of having smtpmail-debug-info t and smtpmail-debug-verb t. There is no info where can I find it.

Question 2: I'm really frustrated now, since 2 days I try to say Emacs to read 16 simple parameter which you can do in the most E-Mail programs in minutes. Is there a possibility to get rid of theseauth-source-netrc-parse-entries mechanism using implicit filenames and showing an a-functional behavior in terms of querying, reporting states and errors, debugging and parsing.

EDIT

file stored as .authinfo.test

machine mx.server1.de login [email protected] password #ABCDE port 587
machine mx.server2.de login [email protected] password #EFGHI port 587
machine mx.server2.de login [email protected] password #4567; port 587
machine smtp.web123.de login web1234 password #1234 port 587

Call

(auth-source-netrc-parse
 :file
   (expand-file-name "~/.authinfo.test"))

auth-source-netrc-parse: using CACHED file data for /Users/i4w/.authinfo.test
if: auth-source-netrc-parse-entries: Unexpected ‘machine’ token at line 2

Debug version of auth-source-netrc-parse

I poked the function out of the auth.el context

(setq auth-source-debug 'trivia)
(defalias 'auth-crab 'auth-source-netrc-parse-entries) 

  
(defun auth-source-netrc-parse-entries(check max)
  "Parse up to MAX netrc entries, passed by CHECK, from the current buffer."
  (auth-source-do-trivia "\nBEGIN.PARSE")
  (let ((adder (lambda(check alist all)
                 (when (and
                        alist
                        (> max (length all))
                        (funcall check alist))
                   (push alist all))
                 all))
        item item2 all alist default)
    
    (while (setq item (auth-source-netrc-parse-one))
      (auth-source-do-trivia "\n  BEGIN.WHILE")
      (auth-source-do-trivia "    PARSED.ITEM: %s" item)
      
      (setq default (equal item "default"))
      (auth-source-do-trivia "    DEFAULT: %s" default)

      ;; We're starting a new machine.  Save the old one.
      (when (and alist
                 (or default
                     (equal item "machine")))

        (auth-source-do-trivia "    COLLECT.MACHINE: %S" alist)

        (setq all (funcall adder check alist all)
              alist nil))
        (auth-source-do-trivia "    RESULT: %S" all)
      
      ;; In default entries, we don't have a next token.
      ;; We store them as ("machine" . t)
      (if default
          (push (cons "default.machine" t) alist)
        ;; Not a default entry.  Grab the next item.
        (auth-source-do-trivia  "    COLLECT.DEFAULT: %S" alist)
        (when (setq item2 (auth-source-netrc-parse-one))
          ;; Did we get a "machine" value?
          (if (equal item2 "machine")
              (progn
                 (auth-source-do-trivia 
                    "    ERROR: %s" (auth-source-current-line))
             (error
              "%s: Unexpected `machine' token at line %d"
              "auth-source-netrc-parse-entries"
              (auth-source-current-line)))
            (push (cons item item2) alist))))
        (auth-source-do-trivia "  END.WHILE\n"))
      

    ;; Clean up: if there's an entry left over, use it.
    (when alist
      (setq all (funcall adder check alist all)))
    
    (auth-source-do-trivia
         "\nEND.PARSE.ALL")
    (auth-source-do-trivia
         "\nRESULT.ALL: %S" (nreverse all))

    (nreverse all)))

Result with the invalid config



auth-source-netrc-parse: using CACHED file data for /Users/i4w/.authinfo.test

BEGIN.PARSE

  BEGIN.WHILE
    PARSED.ITEM: machine
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: nil
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: login
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("machine" . "mx.server1.de"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: password
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("login" . "[email protected]") ("machine" . "mx.server1.de"))
    ERROR: 2
progn: auth-source-netrc-parse-entries: Unexpected ‘machine’ token at line 2

Result with a valid one

machine server1 login [email protected] password PWD.U1 port 587
machine server1 login [email protected] password PWD.U2 port 587
machine server2 login user3 password PWD.U3 port 587
machine server3 login user4 password PWD.U4 port 587

BEGIN.PARSE

  BEGIN.WHILE
    PARSED.ITEM: machine
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: nil
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: login
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("machine" . "server1"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: password
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("login" . "[email protected]") ("machine" . "server1"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: port
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("password" . "PWD.U1") ("login" . "[email protected]") ("machine" . "server1"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: machine
    DEFAULT: nil
    COLLECT.MACHINE: (("port" . "587") ("password" . "PWD.U1") ("login" . "[email protected]") ("machine" . "server1"))
    RESULT: nil
    COLLECT.DEFAULT: nil
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: login
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("machine" . "server1"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: password
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("login" . "[email protected]") ("machine" . "server1"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: port
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("password" . "PWD.U2") ("login" . "[email protected]") ("machine" . "server1"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: machine
    DEFAULT: nil
    COLLECT.MACHINE: (("port" . "587") ("password" . "PWD.U2") ("login" . "[email protected]") ("machine" . "server1"))
    RESULT: nil
    COLLECT.DEFAULT: nil
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: login
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("machine" . "server2"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: password
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("login" . "user3") ("machine" . "server2"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: port
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("password" . "PWD.U3") ("login" . "user3") ("machine" . "server2"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: machine
    DEFAULT: nil
    COLLECT.MACHINE: (("port" . "587") ("password" . "PWD.U3") ("login" . "user3") ("machine" . "server2"))
    RESULT: nil
    COLLECT.DEFAULT: nil
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: login
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("machine" . "server3"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: password
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("login" . "user4") ("machine" . "server3"))
  END.WHILE


  BEGIN.WHILE
    PARSED.ITEM: port
    DEFAULT: nil
    RESULT: nil
    COLLECT.DEFAULT: (("password" . "PWD.U4") ("login" . "user4") ("machine" . "server3"))
  END.WHILE


END.PARSE.ALL

RESULT.ALL: nil
nil

6
  • Your .authinfo syntax is not correct: you're missing the login keyword in front of the username for each entry
    – rpluim
    Commented Feb 15 at 8:30
  • Sorry my fault by creating the pseudo code...
    – huckfinn
    Commented Feb 15 at 9:33
  • I could reproduce the error before, but after your edit it works fine for me.
    – rpluim
    Commented Feb 15 at 9:43
  • Ok here is one, I grabbed out auth-source-netrc-parse which triggers the error and to bring in some parser states to for debugging. The code makes abolute no sense to me especially when the collected data result all is nil see ### EDIT
    – huckfinn
    Commented Feb 15 at 12:08
  • 1
    The netrc format parsed by auth-source is both ancient and not particularly well specified. It's pretty obvious to me from the auth-source manual that you need to put quotes around passwords containing spaces, so by extension comment characters need the same treatment.
    – rpluim
    Commented Feb 15 at 13:48

2 Answers 2

0

The parser auth-source-netrc-parse-entries is intolerant against passwords with special characters which are common in recent days.

This has to be documented! Passwords and other fancy stuff in the values has to be quoted.

The function auth-source-netrc-looking-at-token checks for quotes and white spaces. The function auth-source-netrc-parse-next-interesting rejects/skips LINES/ENTRIES containing the character '#'.

This causes and iteration stop over the character stream in function auth-source-netrc-parse-one which leads to the assumption in function auth-source-netrc-parse-entries that an positional token error occurs.

Summary:

I guess there will be a feature vs. bug discussion. Anyway the error message Unexpected ‘machine’ token at line XX is completely missleading. I think this should be rewritten, because there is no distinction between positional token and values. So the generation of a proper error message is complicated.

At least the documentation beyond the all the GPG focused descriptions should mention, that values like passwords and names should and can be QUOTED!

Token check and reader from auth.el

(defun auth-source-netrc-looking-at-token ()
  "Say whether the next think in the buffer is a token (password, etc).
Match data is altered to reflect the token."
  (or (looking-at "'\\([^']*\\)'")
      (looking-at "\"\\([^\"]*\\)\"")
      (looking-at "\\([^ \t\n]+\\)")))

(defun auth-source-netrc-parse-one ()
  "Read one thing from the current buffer."
  (auth-source-netrc-parse-next-interesting)

  (when (auth-source-netrc-looking-at-token)
    (forward-char (length (match-string 0)))
    (prog1
        (match-string-no-properties 1)
      (auth-source-netrc-parse-next-interesting))))

(defun auth-source-netrc-parse-next-interesting ()
  "Advance to the next interesting position in the current buffer."
  (skip-chars-forward "\t ")
  ;; If we're looking at a comment or are at the end of the line, move forward
  (while (or (eq (char-after) ?#) ;; <----- HERE 
             (and (eolp)
                  (not (eobp))))
    (forward-line 1)              ;; <----- HERE
    (skip-chars-forward "\t ")))

0

Not an answer, only an observation (or confirmation) that the parser is broken as the same error is observed when using this example:

machine hosty.example.com login anonymous password "[email protected]"
macdef init
bell
hash
binary

machine hostx.example.com login ftp password "[email protected]"
macdef init
bell
hash
passive
binary

Reverse the order and it works. Seems to be related to the number of words following the machine line; either adding or removing a word from hosty will cause it to pass and not error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.