#
# $Id: quotedprintablehandler.icn,v 1.1 2004/02/12 17:07:56 rparlett Exp $
#

package mail

import util

#
# Handles the quoted-printable encoding of a message
#
class QuotedPrintableHandler:EncodingHandler(res, ll)
   method can_handle(enc)
      return map(enc) == "quoted-printable"
   end

   method encode_data(m, data)
      static quotable_chars
      initial {
         quotable_chars := cset(&ascii[33:62] || &ascii[63:128])
      }

      res := ""
      ll := 0

      data ? {
         while not pos(0) do {
            if s := tab(many(quotable_chars)) then {
               if pos(0) & any(' \t', s[-1]) then {
                  put(s[1:-1])
                  escape(s[-1])
               } else {
                  put(s)
               }
            } else if ="\r\n" then {
               nl()
            } else {
               escape(move(1))
            }
         }
      }

      return res
   end

   # @p
   method escape(ch)
      local t
      t := "=" || format_int_to_string(ord(ch), 16, 2)
      if ll > 72 then {
         res ||:= "="
         nl()
      }
      res ||:= t
      ll +:= 3
      return
   end

   # @p
   method nl()
      res ||:= "\r\n"
      ll := 0
      return
   end

   # @p
   method put(s)
      local lim
      repeat {
         lim := 75 - ll
         if *s > lim then {
            res ||:= s[1:lim+1] || "="
            nl()
            s := s[lim+1:0]
         } else {
            res ||:= s
            ll +:= *s
            return
         }
      }
   end

   method decode_data(m, data) 
      local res
      res := ""
      data ? repeat {
         res ||:= tab(upto('\r=') | 0)
         if pos(0) then
            break
         if any('=') then {
            move(1)
            # If not a soft line break, then unescape the =XX format.
            if not ="\r\n" then {
               res ||:= char(format_string_to_int(move(2))) | return error("Bad quoted-printable data")
            }
         } else
            res ||:= ="\r\n" | return error("Bad quoted-printable data")
      }
      return res
   end
end