texmailer 0.1 → 0.2.d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/texmailer CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ TMVERSION = '0.2.d'
3
+
2
4
  require 'rubygems'
3
5
  require 'ftools'
4
6
  require 'erb'
@@ -14,6 +16,8 @@ require 'texmailer/drafts'
14
16
  require 'texmailer/config'
15
17
  require 'texmailer/send'
16
18
  require 'texmailer/wapp'
19
+ require 'texmailer/iview'
20
+ require 'texmailer/adbook'
17
21
 
18
22
  include Texmailer
19
23
 
@@ -22,12 +26,14 @@ $basedir = libdir + '/texmailer'
22
26
  # Parse Options
23
27
  theport = 6213
24
28
  $userdir = '~/.texmailer'
29
+ daemonize = true
25
30
 
26
31
  opt = OptionParser.new { |opts|
27
32
  opts.banner = "Usage: texmailer [options]"
28
33
  opts.on("-p PORT","--port PORT",Integer,"Port to listen on (default #{String(theport)})") { |p| theport = p }
29
34
  opts.on("-u DIRECTORY","--userdir DIRECTORY","User directory (default #{$userdir})") { |p| $userdir = p }
30
-
35
+ opts.on("-n","--no-daemon","Do not send to background") {daemonize = false}
36
+ opts.version = TMVERSION
31
37
  opts.on_tail("-h","--help","Displays this help message") {
32
38
  puts opt
33
39
  exit(1)
@@ -41,6 +47,11 @@ rescue
41
47
  end
42
48
 
43
49
  $userdir = File.expand_path($userdir)
50
+
51
+ $iv = Iview.new $userdir
52
+ $ab = Adbook.new $userdir
53
+ $iv.upabook
54
+
44
55
  # Make user directories if they don't exist
45
56
  begin
46
57
  Dir.mkdir($userdir,0700) if ! File.directory? $userdir
@@ -52,18 +63,24 @@ rescue
52
63
  end
53
64
 
54
65
  # Run webserver, fork and die
55
- begin
56
- Rack::Handler::Mongrel.run(webapp, :Host=>"127.0.0.1", :Port=>theport) { |x|
57
- if pid = Kernel.fork then
58
- Process.detach(pid)
59
- puts "Server running with PID=#{String(pid)}\n"
60
- puts "Go to http://127.0.0.1:#{String(theport)}/ to send LaTeX-ed mail!\n"
61
- exit(0)
62
- end
66
+ begin
67
+ if daemonize then
68
+ Rack::Handler::Mongrel.run(webapp, :Host=>"127.0.0.1", :Port=>theport) { |x|
69
+ if pid = Kernel.fork then
70
+ Process.detach(pid)
71
+ puts "Server running with PID=#{String(pid)}\n"
72
+ puts "Go to http://127.0.0.1:#{String(theport)}/ to send LaTeX-ed mail!\n"
73
+ exit(0)
74
+ end
63
75
 
64
- $stderr.reopen('/dev/null','w')
65
- $stdout.reopen('/dev/null','w')
66
- }
76
+ $stderr.reopen('/dev/null','w')
77
+ $stdout.reopen('/dev/null','w')
78
+ }
79
+ else
80
+ Rack::Handler::Mongrel.run(webapp, :Host=>"127.0.0.1", :Port=>theport) { |x|
81
+ puts "Go to http://127.0.0.1:#{String(theport)}/ to send LaTeX-ed mail!\n"
82
+ }
83
+ end
67
84
  rescue
68
85
  STDERR.write "Could not listen on port #{String(theport)}. Make sure texmailer is not already running and that you have permissions.\n"
69
86
  exit(1)
@@ -0,0 +1,98 @@
1
+ require 'texmailer/iview'
2
+ require 'net/imap'
3
+
4
+ module Texmailer
5
+
6
+ ABVERSION = '0.1'
7
+
8
+ class Adbook
9
+
10
+ def initialize userdir
11
+ @afile = userdir+'/abook.dat'
12
+ if File.readable? @afile
13
+ data = Marshal.load(File.read(@afile))
14
+ @ab = data[1] if data[0] == ABVERSION
15
+ end
16
+ @ab ||= {}
17
+ end
18
+
19
+ def save
20
+ s = Marshal.dump([ABVERSION,@ab])
21
+ File.open(@afile,'w',0600) {|f| f.write s}
22
+ end
23
+
24
+
25
+ def search q
26
+ subs = {}
27
+ lg = q.length-1
28
+ query= q.upcase
29
+ @ab.each_pair { |em,nm|
30
+ if em[0..lg].upcase == query
31
+ subs[em] = nm
32
+ else
33
+ nm.split(" ").each { |x|
34
+ if x[0..lg].upcase == query
35
+ subs[em] = nm
36
+ break
37
+ end
38
+ }
39
+ end
40
+ }
41
+ lst = subs.to_a.collect{ |x|
42
+ nstr = x[1].strip
43
+ nstr = '"' + nstr + '" ' if nstr.length > 0
44
+ '\''+ nstr + '<'+x[0]+'>\''
45
+ }
46
+ return lst.join(",")
47
+ end
48
+
49
+ def upemail name,email
50
+ name = '' if name[0..0] == '='
51
+ @ab[email] = name if !(ename = @ab[email]) || ename.length < name.length
52
+ end
53
+
54
+ def uptolist em
55
+ arr = []
56
+ pfx = ''
57
+ while m = /[\,\"]/.match(em)
58
+ if m[0] == ','
59
+ arr = arr + [(pfx + m.pre_match).strip]
60
+ pfx = ''
61
+ em = m.post_match
62
+ elsif m2 = /[^\\]\"/.match(m.post_match)
63
+ pfx = pfx + m.pre_match + m[0] + m2.pre_match + m2[0]
64
+ em = m2.post_match
65
+ else
66
+ pfx = pfx + em
67
+ em = ''
68
+ end
69
+ end
70
+ if (s = (pfx+em).strip).length > 0
71
+ arr = arr + [s]
72
+ end
73
+ arr.each { |x|
74
+ if m = /.*?\"(.*?[^\\])\"\s*<([^@\s]*?@[^@\s]*?)>/.match(x)
75
+ upemail m[1].strip, m[2].strip
76
+ elsif m = /(.*?)<([^@]*?@[^@]*?)>/.match(x)
77
+ upemail m[1].strip, m[2].strip
78
+ elsif m = /[^\s\"]*?@[^\s\"]*/.match(x)
79
+ upemail '', m[0]
80
+ end
81
+ }
82
+ end
83
+
84
+ def upenv evs
85
+ evs.each { |x|
86
+ [x.from, x.to, x.cc].each { |y|
87
+ y.each { |z|
88
+ upemail z.name||'', z.mailbox+"@"+z.host
89
+ } if y
90
+ }
91
+ }
92
+ save
93
+ end
94
+
95
+ end
96
+
97
+
98
+ end
@@ -1,5 +1,53 @@
1
1
  module Texmailer
2
2
 
3
+ # From list
4
+ def loadflist
5
+ f = $userdir + "/flist.cfg"
6
+ return '' if ! File.readable? f
7
+ return File.read(f)
8
+ end
9
+
10
+ def getlist flist
11
+ return [] if ! flist
12
+ flist.strip!
13
+ return [] if flist.length == 0
14
+ a = flist.split(",")
15
+ a.collect! {|x|
16
+ x.gsub(/\s/,'').gsub(/[\<\>]/,'')
17
+ }
18
+ end
19
+
20
+ def saveflist req
21
+ g = getlist req["flist"]
22
+ File.open($userdir + "/flist.cfg","w",0600) { |f| f.write g.join(', ')}
23
+ end
24
+
25
+ # IMAP Parameters
26
+ def loadiparams
27
+ p = $iv.getsettings
28
+
29
+ ['host','port','ssl','igcert','user','password'].each { |x|
30
+ p[x] = String(p[x]) if p[x]
31
+ p[x] ||= 'false' if x == 'ssl' || x == 'igcert'
32
+ p[x] ||= ''
33
+ }
34
+ return p
35
+ end
36
+
37
+ def saveiparams req
38
+ p = Hash.new
39
+ ['host','user','password'].each { |x|
40
+ p[x] = req[x] if req[x]
41
+ p[x] ||= ''
42
+ }
43
+ p['port'] = Integer(req['port']) rescue
44
+ p['port'] ||= 143
45
+ p['ssl'] = req['ssl'] ? true : false
46
+ p['igcert'] = req['igcert'] ? true : false
47
+ $iv.savesettings p
48
+ end
49
+
50
+ # SMTP Parameters
3
51
  def loadparams
4
52
  p = Hash.new
5
53
  params = [['from',0],['mailfrom', 0],['host', 0],['port', 0],['ssl', 1],['igcert', 1],['auth', 1],['user', 0],['pass', 0]]
@@ -11,7 +59,7 @@ module Texmailer
11
59
  p[params[i-1][0]] = lns[i-1].sub(/\n/m,'')
12
60
  }
13
61
  end
14
- p.inspect
62
+
15
63
  params.each { |x| p[x[0]] ||= '' }
16
64
  params.each { |x| p[x[0]] == 'false' if x[1] == 1 && p[x[0]] != 'true' }
17
65
  return p
@@ -57,12 +105,16 @@ module Texmailer
57
105
  def msmtp(req,message)
58
106
  fnm = makerc
59
107
  pr = loadparams
108
+ svdir = $userdir+"/drafts/"+req["mailid"]
109
+
60
110
  IO.popen("msmtp -C #{fnm} -t 2> #{$userdir}/msmtplog","w") { |p|
61
111
  [ ["To:","mailto"],["CC:","mailcc"],["BCC:","mailbcc"],["Subject:","subject"] ].each { |x|
62
112
  if req[x[1]] && req[x[1]].length > 0 then
63
113
  p.write x[0] + " " + req[x[1]].gsub(/\n/m,'') + "\n"
64
114
  end
65
115
  }
116
+ p.write(File.read(svdir+"/exhdr") + "\n") if File.readable? svdir+"/exhdr"
117
+
66
118
  if pr["from"].length > 0 then
67
119
  p.write "From: #{pr["from"]} <#{pr["mailfrom"]}>\n"
68
120
  end
@@ -1,7 +1,19 @@
1
1
  require 'cgi'
2
+ require 'time'
3
+ require 'net/imap'
4
+ require 'texmailer/config'
2
5
 
3
6
  module Texmailer
4
7
 
8
+ def shortem(emlst)
9
+ emlst = emlst.gsub(/\s+/,' ')
10
+ r = /(\".*?\")\s*\<([^\>]*)\>/
11
+ a = emlst.gsub(r) {
12
+ Regexp.last_match[1].gsub('"','')
13
+ }
14
+ return a
15
+ end
16
+
5
17
  def savedraft(mailid,req)
6
18
  svdir = $userdir + '/drafts/'+mailid
7
19
  if ! File.directory? svdir
@@ -10,8 +22,92 @@ module Texmailer
10
22
  ["mailto","mailcc","mailbcc","subject","body"].each { |s|
11
23
  File.open(svdir+'/'+s,"w") { |f| f.write req[s] }
12
24
  }
25
+ ["mailto","mailcc","mailbcc"].each { |s|
26
+ $ab.uptolist req[s]
27
+ }
13
28
  end
14
29
 
30
+ def makereply(cache,mailid)
31
+ p = loadparams
32
+ mfrom = p["mailfrom"]
33
+ mfrom = [mfrom] + getlist(loadflist)
34
+
35
+ evl = cache[0]
36
+ to = [evl.reply_to[0]] if evl.reply_to.length > 0
37
+ to ||= [evl.from[0]] if evl.from
38
+ to ||= []
39
+ cc = evl.cc
40
+ cc ||= []
41
+
42
+ if to.length == 0
43
+ to = to + evl.to if evl.to
44
+ else
45
+ cc = cc + evl.to if evl.to
46
+ end
47
+
48
+ [to,cc].each { |em|
49
+ em.collect! { |x|
50
+ addr = x.mailbox+"@"+x.host
51
+ mine = false
52
+ mfrom.each {|y| mine = true if y == addr}
53
+ if mine
54
+ nil
55
+ else
56
+ if x.name && x.name.length > 0 && x.name[0..0] != '='
57
+ "\"#{x.name}\" <#{addr}>"
58
+ else
59
+ addr
60
+ end
61
+ end
62
+ }
63
+ em.compact!
64
+ }
65
+
66
+ if evl.from
67
+ x = evl.from[0]
68
+ addr = x.mailbox+"@"+x.host
69
+ addr.gsub!('_','\\_')
70
+ sender = if x.name && x.name.length > 0 && x.name[0..0] != '='
71
+ "#{x.name} ``#{addr}\""
72
+ else
73
+ addr
74
+ end
75
+ end
76
+ sender ||= 'No Name'
77
+
78
+ if evl.subject && evl.subject.length > 0
79
+ subj = evl.subject
80
+ subj = "Re: "+subj if subj.length < 3 || subj[0..2].upcase != 'RE:'
81
+ else
82
+ subj = "Re: your mail"
83
+ end
84
+
85
+ exhdr = "In-Reply-To: " + evl.message_id if evl.message_id
86
+
87
+ svdir = $userdir + '/drafts/'+mailid
88
+ if ! File.directory? svdir
89
+ Dir.mkdir(svdir)
90
+ end
91
+
92
+ File.open(svdir+"/mailto","w") {|f| f.write to.join(",")} if to.length > 0
93
+ File.open(svdir+"/mailcc","w") {|f| f.write cc.join(",")} if cc.length > 0
94
+ File.open(svdir+"/subject","w") {|f| f.write subj}
95
+ File.open(svdir+"/exhdr","w") {|f| f.write exhdr} if evl.message_id
96
+
97
+ if cache[1].length > 0
98
+ dstr = 'On ' + evl.date.to_s + ' ' if evl.date
99
+ dstr ||= ''
100
+ qtext = "\\reply{\n" + dstr + sender + " wrote:\n\n"
101
+ if ! cache[1][0]
102
+ qtext = qtext + "\\begin{verbatim}\n"+cache[1][1]+"\n\\end{verbatim}\n}\n"
103
+ else
104
+ qtext = qtext + cache[1][1] + "\n}\n"
105
+ end
106
+ File.open(svdir+"/body","w") {|f| f.write "\n\n"+qtext}
107
+ end
108
+ end
109
+
110
+
15
111
  def getpvloc(mailid)
16
112
  pvlnk = '/preview/' + mailid + '/t.html'
17
113
  return pvlnk if File.readable? $userdir+pvlnk
@@ -24,19 +120,49 @@ module Texmailer
24
120
  Dir.mkdir(pvdir)
25
121
  end
26
122
 
123
+ body = req["body"]
124
+
27
125
  s = <<EOF
28
- \\documentclass{article}
126
+ \\documentclass[10pt]{article}
29
127
  \\usepackage{amsmath,amssymb}
30
128
  \\setlength{\\parindent}{0in}
129
+ \\newcommand{\\reply}[1]{\\begin{quotation}
130
+ \\setlength{\\parindent}{0in}
131
+ #1
132
+ \\end{quotation}
133
+ }
31
134
  \\begin{document}
32
- #{req["body"]}
135
+ #{body}
33
136
  \\end{document}
34
137
  EOF
138
+ vblocks = []
139
+ s2 = ''
140
+ while m = /\\begin\{verbatim\}/.match(s)
141
+ rstring = (0...15).map{ ('A'..'Z').to_a[rand(26)] }.join + "\n";
142
+ s2 = s2 + m.pre_match + rstring
143
+ s = m.post_match
144
+ if m2 = /\\end\{verbatim\}/.match(s)
145
+ s = m2.post_match
146
+ vstring = m2.pre_match
147
+ else
148
+ vstring = s
149
+ s = ''
150
+ end
151
+ vstring = CGI.escapeHTML(vstring).gsub("\n","<br>\n")
152
+ vblocks = vblocks + [ [rstring,vstring]]
153
+ end
154
+ s = s2 + s
35
155
  File.open(pvdir + '/t.tex','w') { |f| f.write s}
36
156
  Dir.chdir(pvdir);
37
157
 
158
+
38
159
  if system('latex -interaction=nonstopmode t > ltxrun.txt 2>/dev/null')
39
160
  system('htlatex t > /dev/null 2>/dev/null')
161
+ html = File.read(pvdir+'/t.html')
162
+ html.gsub!(/\<body.*?>/m) { |m| m + '<div style="font-family: Helvetica, Arial, sans-serif; font-size: 14px">' }
163
+ html.gsub!('</body>','</body></div>')
164
+ vblocks.each { |vb| html.gsub!(vb[0],vb[1]) }
165
+ File.open(pvdir+'/t.html','w') { |f| f.write html}
40
166
  return true
41
167
  else
42
168
  emsg = File.read(pvdir+'/ltxrun.txt');
@@ -69,6 +195,7 @@ EOF
69
195
  lst.each {|f| File.delete(f)}
70
196
  Dir.rmdir(svdir)
71
197
  end
198
+ Dir.chdir($userdir)
72
199
 
73
200
  end
74
201
 
@@ -90,13 +217,49 @@ EOF
90
217
  subject ||= ''
91
218
  subject = '(No Subject)' if subject.length == 0
92
219
 
93
- [mid,CGI.escapeHTML(mailto),CGI.escapeHTML(subject),drtime]
220
+ [mid,CGI.escapeHTML(shortem(mailto)),CGI.escapeHTML(subject),drtime]
94
221
  end
95
222
  }
96
223
  s.compact!
97
224
  s.sort! {|a,b| b[3] <=> a[3]}
98
225
  return s
99
226
  end
227
+
228
+
229
+ def nicecache cache
230
+ msgs = cache.sort { |m,l| Time.parse(l[1][0].date) <=> Time.parse(m[1][0].date) }
231
+ msgs.collect! { |x|
232
+ uid = x[0]
233
+ evl = x[1][0]
234
+ bdy = x[1][1][1]
235
+
236
+ from = evl.from[0].name if evl.from[0].name && evl.from[0].name.length > 0 && evl.from[0].name[0..0] != '='
237
+ from ||= (evl.from[0].mailbox + "@" + evl.from[0].host) if evl.from[0].mailbox && evl.from[0].host
238
+ from ||= "Unknown Sender"
239
+ if from.length > 26
240
+ from = from.split(/[@ ]/)[0]
241
+ end
242
+
243
+ maxsb = 95
244
+ subject = evl.subject.gsub(/[\s]+/m, ' ').strip if evl.subject
245
+ subject ||= '(no subject)'
246
+ bdy.gsub!(/^\>.*/,'')
247
+ if bdy.length > 0 && subject.length < maxsb && m = /[A-Za-z]/.match(bdy)
248
+ bdy = m[0] + m.post_match
249
+ bdy = bdy.gsub!(/\s+/m,' ').strip
250
+ if bdy.length > maxsb-subject.length
251
+ bdy = bdy[0..(maxsb-subject.length-1)]
252
+ end
253
+ subject = CGI.escapeHTML(subject)+'<span style="color:#999999">: &nbsp;'+CGI.escapeHTML(bdy)+"</span>"
254
+ else
255
+ subject = CGI.escapeHTML(subject)
256
+ end
257
+
258
+ sdate = Time.parse(evl.date).to_nice_s
259
+ [uid,from,subject,sdate]
260
+ }
261
+ end
262
+
100
263
  end
101
264
 
102
265
  ## Borrowed from sup