texmailer 0.1 → 0.2.d

Sign up to get free protection for your applications and to get access to all the features.
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