1 |
/* |
2 |
openisis - an open implementation of the CDS/ISIS database |
3 |
Version 0.8.x (patchlevel see file Version) |
4 |
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org |
5 |
|
6 |
This library is free software; you can redistribute it and/or |
7 |
modify it under the terms of the GNU Lesser General Public |
8 |
License as published by the Free Software Foundation; either |
9 |
version 2.1 of the License, or (at your option) any later version. |
10 |
|
11 |
This library is distributed in the hope that it will be useful, |
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
Lesser General Public License for more details. |
15 |
|
16 |
You should have received a copy of the GNU Lesser General Public |
17 |
License along with this library; if not, write to the Free Software |
18 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
|
20 |
see README for more information |
21 |
EOH */ |
22 |
|
23 |
package org.openisis; |
24 |
|
25 |
import java.io.*; |
26 |
import java.util.*; |
27 |
|
28 |
import javax.activation.*; |
29 |
import javax.mail.*; |
30 |
import javax.mail.internet.*; |
31 |
|
32 |
|
33 |
/** |
34 |
This class contains a collection of javax.mail based E-Mail utilities. |
35 |
|
36 |
<p> |
37 |
$Id: Mail.java,v 1.4 2003/04/08 00:20:53 kripke Exp $ |
38 |
@version $Revision: 1.4 $ |
39 |
@author $Author: kripke $ |
40 |
*/ |
41 |
public abstract class Mail { |
42 |
|
43 |
public static final String EMPTY = ""; |
44 |
|
45 |
public static final String MESSAGEID = "message-id"; |
46 |
public static final String DATE = "date"; |
47 |
public static final String TO = "to"; |
48 |
public static final String CC = "cc"; |
49 |
public static final String BCC = "bcc"; |
50 |
public static final String FROM = "from"; |
51 |
public static final String SENDER = "sender"; |
52 |
public static final String REPLYTO = "reply-to"; |
53 |
public static final String SUBJECT = "subject"; |
54 |
public static final String REFERENCES = "references"; |
55 |
public static final String INREPLYTO = "in-reply-to"; |
56 |
public static final String KEYWORDS = "keywords"; |
57 |
public static final String COMMENTS = "comments"; |
58 |
public static final String ENCRYPTED = "encrypted"; |
59 |
public static final String PRECEDENCE = "precedence"; // non-standard |
60 |
public static final String XPRIORITY = "x-priority"; // non-standard |
61 |
public static final String RETURNPATH = "return-path"; |
62 |
public static final String DLVRDTO = "delivered-to"; // qmail |
63 |
public static final String RECEIVED = "received"; |
64 |
public static final String XMAILER = "x-mailer"; |
65 |
public static final String CTYPE = "content-type"; |
66 |
public static final String CTRANSENC = "content-transfer-encoding"; |
67 |
|
68 |
public static final String TEXT_PLAIN = "text/plain"; |
69 |
public static final String TEXT_ISO = "text/plain; charset=\"iso-8859-1\""; |
70 |
public static final String TEXT_HTML = "text/html"; |
71 |
public static final String MESS_MIME = "message/rfc822"; |
72 |
public static final String MULT_MIXED = "multipart/mixed"; |
73 |
public static final String MULT_ALT = "multipart/alternative"; |
74 |
public static final String MULT_APPLE = "multipart/appledouble"; |
75 |
public static final String MULT_SIGN = "multipart/signed"; |
76 |
public static final String MULT_ANY = "multipart/*"; |
77 |
public static final String APPL_WORD = "application/msword"; |
78 |
public static final String APPL_PDF = "application/pdf"; |
79 |
public static final String APPL_RTF = "application/rtf"; |
80 |
public static final String APPL_BYTES = "application/octet-stream"; |
81 |
public static final String APPL_APPLE = "application/applefile"; |
82 |
public static final String APPL_ANY = "application/*"; |
83 |
public static final String IMAG_GIF = "image/gif"; |
84 |
public static final String IMAG_JPEG = "image/jpeg"; |
85 |
public static final String IMAG_ANY = "image/*"; |
86 |
|
87 |
public static final String SMTP_HOST = "mail.smtp.host"; |
88 |
|
89 |
public static final Session SES; |
90 |
static { |
91 |
if ( null == System.getProperty( SMTP_HOST ) ) |
92 |
System.setProperty( SMTP_HOST, "localhost" ); |
93 |
SES = Session.getDefaultInstance( System.getProperties(), null ); |
94 |
} |
95 |
|
96 |
|
97 |
public static interface Source { |
98 |
Message[] get () throws Exception; |
99 |
void done ( boolean expunge ) throws Exception; |
100 |
} |
101 |
|
102 |
public static interface Sink { |
103 |
void put ( Message m ) throws Exception; |
104 |
void put ( Message[] m ) throws Exception; |
105 |
} |
106 |
|
107 |
|
108 |
// ////////////////////////////////////////////////// |
109 |
// utilities |
110 |
// |
111 |
|
112 |
public static void del ( Message m ) |
113 |
throws Exception |
114 |
{ |
115 |
m.setFlag( Flags.Flag.DELETED, true ); |
116 |
} // del |
117 |
|
118 |
public static void del ( Message[] m ) |
119 |
throws Exception |
120 |
{ |
121 |
for ( int i=0; i<m.length; i++ ) |
122 |
if ( null != m[i] ) |
123 |
m[i].setFlag( Flags.Flag.DELETED, true ); |
124 |
} // del |
125 |
|
126 |
|
127 |
public static void put ( Sink s, Message[] m ) |
128 |
throws Exception |
129 |
{ |
130 |
for ( int i=0; i<m.length; i++ ) |
131 |
if ( null != m[i] ) |
132 |
s.put( m[i] ); |
133 |
} // put |
134 |
|
135 |
public static int move ( Sink si, Source so ) |
136 |
throws Exception |
137 |
{ |
138 |
Message[] m; |
139 |
int copied = 0; |
140 |
while ( null != (m = so.get()) && 0 < m.length ) { |
141 |
si.put( m ); |
142 |
del( m ); |
143 |
so.done( true ); |
144 |
copied += m.length; |
145 |
} |
146 |
return copied; |
147 |
} // move |
148 |
|
149 |
public static String head ( Part p, String name, String def ) |
150 |
throws Exception |
151 |
{ |
152 |
String[] hh = p.getHeader( name ); |
153 |
return null == hh || 0 == hh.length ? def : hh[0]; |
154 |
} // head |
155 |
|
156 |
public static String head ( Part p, String name ) |
157 |
throws Exception |
158 |
{ |
159 |
return head( p, name, null ); |
160 |
} // head |
161 |
|
162 |
// join lines, commonly used for content type |
163 |
public static String oneline ( String ct ) |
164 |
{ |
165 |
return null == ct ? null : ct.replace( '\n', '\t' ).replace( '\r', ' ' ); |
166 |
} // oneline |
167 |
|
168 |
public static Message message ( String[] headers, String body ) |
169 |
throws Exception |
170 |
{ |
171 |
MimeMessage mm = new MimeMessage( SES ); |
172 |
for ( int i=0; i<headers.length; i+=2 ) |
173 |
mm.addHeader( headers[i], headers[i+1] ); |
174 |
mm.addHeader( CTYPE, TEXT_ISO ); |
175 |
mm.setContent( body, TEXT_ISO ); |
176 |
if ( null == mm.getSentDate() ) |
177 |
mm.setSentDate( new Date() ); |
178 |
return mm; |
179 |
} |
180 |
|
181 |
// ////////////////////////////////////////////////// |
182 |
// implementations |
183 |
// |
184 |
|
185 |
public static class Pop implements Source { |
186 |
static final FetchProfile FPEMPTY = new FetchProfile(); |
187 |
Store _store; |
188 |
Folder _f; |
189 |
String _h; |
190 |
int _o; |
191 |
String _u; |
192 |
String _p; |
193 |
int _max; |
194 |
|
195 |
public Pop ( String host, int port, String user, String pass, int max ) |
196 |
throws Exception |
197 |
{ |
198 |
_store = SES.getStore( "pop3" ); |
199 |
_h = host; |
200 |
_o = port; |
201 |
_u = user; |
202 |
_p = pass; |
203 |
_max = max; |
204 |
} |
205 |
|
206 |
public Pop ( String host, String user, String pass, int max ) |
207 |
throws Exception |
208 |
{ |
209 |
this( host, 110, user, pass, max ); |
210 |
} |
211 |
|
212 |
public Pop ( String host, String user, String pass ) |
213 |
throws Exception |
214 |
{ |
215 |
this( host, user, pass, 0 ); |
216 |
} |
217 |
|
218 |
public Message[] get () |
219 |
throws Exception |
220 |
{ |
221 |
_store.connect( _h, _o, _u, _p ); |
222 |
_f = _store.getFolder( "INBOX" ); // the magic default folder |
223 |
_f.open( Folder.READ_WRITE ); |
224 |
Message[] m = _f.getMessages(); |
225 |
System.err.println( "pop "+_u+"@"+_h+":"+_o+" new " |
226 |
+ (null==m ? -1 : m.length) ); |
227 |
if ( null == m ) |
228 |
return null; |
229 |
if ( 0 != _max && _max < m.length ) { |
230 |
Message[] mm = new Message[_max]; |
231 |
System.arraycopy( m, 0, mm, 0, _max ); |
232 |
m = mm; |
233 |
} |
234 |
_f.fetch( m, FPEMPTY ); |
235 |
System.err.println( "pop "+_u+"@"+_h+":"+_o+" got "+m.length ); |
236 |
return m; |
237 |
} |
238 |
|
239 |
public void done ( boolean expunge ) |
240 |
throws Exception |
241 |
{ |
242 |
if ( null != _f ) { |
243 |
_f.close( expunge ); |
244 |
_f = null; |
245 |
} |
246 |
_store.close(); |
247 |
} |
248 |
} // class Pop |
249 |
|
250 |
|
251 |
public static class Dir implements Source, Sink { // the Maildir |
252 |
final String _t; |
253 |
final String _n; |
254 |
final String _c; |
255 |
final File _ndir; |
256 |
int _lim; |
257 |
|
258 |
Msg[] got; |
259 |
|
260 |
class Msg extends MimeMessage { |
261 |
final File _f; |
262 |
Msg ( File f ) |
263 |
throws Exception |
264 |
{ |
265 |
super( SES, new FileInputStream( f ) ); |
266 |
_f = f; |
267 |
System.err.println( "file "+f.getName() |
268 |
+": "+head( this, MESSAGEID, "<?>" ) ); |
269 |
} |
270 |
} |
271 |
|
272 |
public Dir ( String base ) |
273 |
throws Exception |
274 |
{ |
275 |
_t = base + File.separator + "tmp"; |
276 |
_n = base + File.separator + "new"; |
277 |
_c = base + File.separator + "cur"; |
278 |
_ndir = new File(_n); |
279 |
File t = new File(_t); |
280 |
File c = new File(_c); |
281 |
if ( ! t.isDirectory() && ! t.mkdirs() ) |
282 |
throw new FileNotFoundException( _t ); |
283 |
if ( ! _ndir.isDirectory() && ! _ndir.mkdirs() ) |
284 |
throw new FileNotFoundException( _n ); |
285 |
if ( ! c.isDirectory() && ! c.mkdirs() ) |
286 |
throw new FileNotFoundException( _c ); |
287 |
} |
288 |
|
289 |
public String toString () { |
290 |
return "Dir "+_ndir.getParentFile().getAbsolutePath(); |
291 |
} |
292 |
|
293 |
|
294 |
public Message[] get () throws Exception |
295 |
{ |
296 |
File[] l = _ndir.listFiles(); |
297 |
System.err.println( _ndir+": "+l.length ); |
298 |
int i = l.length; |
299 |
if ( 0 != _lim && i > _lim ) |
300 |
i = _lim; |
301 |
got = new Msg[i]; |
302 |
while ( 0 < i-- ) { |
303 |
File f = new File( _t+File.separator+l[i].getName() ); |
304 |
l[i].renameTo( f ); |
305 |
got[i] = new Msg( f ); |
306 |
} |
307 |
return got; |
308 |
} |
309 |
|
310 |
public void done ( boolean expunge ) throws Exception |
311 |
{ |
312 |
if ( expunge && null != got ) |
313 |
for ( int i=0; i<got.length; i++ ) |
314 |
if ( got[i].isSet( Flags.Flag.DELETED ) ) |
315 |
got[i]._f.delete(); |
316 |
got = null; |
317 |
} |
318 |
|
319 |
|
320 |
public void put ( Message m ) |
321 |
throws Exception |
322 |
{ |
323 |
File f; |
324 |
String s = File.separator+System.currentTimeMillis(); |
325 |
while ( ! (f = new File( _t + s )).createNewFile() ) |
326 |
s += (int)(10*Math.random()) % 10; |
327 |
OutputStream o = new FileOutputStream(f); |
328 |
m.writeTo( o ); |
329 |
o.close(); |
330 |
while ( ! f.renameTo(new File( _n + s )) ) |
331 |
s += (int)(10*Math.random()) % 10; |
332 |
} |
333 |
|
334 |
public void put ( Message[] m ) |
335 |
throws Exception |
336 |
{ |
337 |
Mail.put( this, m ); |
338 |
} |
339 |
} // class Dir |
340 |
|
341 |
|
342 |
public static class Arc implements Sink { // the archive |
343 |
static final String OK = "ok"; |
344 |
static final Map OKHDR = new HashMap(); |
345 |
static { |
346 |
OKHDR.put( MESSAGEID, OK ); |
347 |
OKHDR.put( DATE, OK ); |
348 |
OKHDR.put( FROM, OK ); |
349 |
OKHDR.put( REPLYTO, OK ); |
350 |
OKHDR.put( SUBJECT, OK ); |
351 |
OKHDR.put( REFERENCES, OK ); |
352 |
OKHDR.put( INREPLYTO, OK ); |
353 |
OKHDR.put( KEYWORDS, OK ); |
354 |
OKHDR.put( COMMENTS, OK ); |
355 |
} |
356 |
|
357 |
final String _u; |
358 |
final String _b; |
359 |
final Sink _fwd; |
360 |
|
361 |
final int _maxlines = 60; |
362 |
final int _minlines = 15; |
363 |
final boolean _zip = true; |
364 |
|
365 |
|
366 |
/** path is /m/d/h/xxx. |
367 |
january is Calendar.JANUARY, which is 0 |
368 |
*/ |
369 |
public static String path ( int mon, int day, int hour, int min, int sec ) |
370 |
{ |
371 |
char mo = (char)('a'+mon); |
372 |
char d = (char)(day + (day<10 ? '0' : 'a'-10)); |
373 |
char h = (char)('a'+hour); |
374 |
int hs = 60*min + sec; |
375 |
sec = hs - 100*(min = hs / 100); |
376 |
char m = (char)(min + (min<10 ? '0' : 'a'-10)); |
377 |
return File.separator+mo + File.separator+d +File.separator+h |
378 |
+ File.separator+m+(char)('0'+sec/10)+(char)('0'+sec%10); |
379 |
} // path |
380 |
|
381 |
public static String path ( Calendar c ) |
382 |
{ |
383 |
return path( c.get( Calendar.MONTH ), c.get( Calendar.DATE ), |
384 |
c.get( Calendar.HOUR_OF_DAY ), c.get( Calendar.MINUTE ), |
385 |
c.get( Calendar.SECOND ) ); |
386 |
} // path |
387 |
|
388 |
public static String path ( Date d ) |
389 |
{ |
390 |
Calendar c = new GregorianCalendar(); |
391 |
c.setTime( d ); |
392 |
return path( c ); |
393 |
} // path |
394 |
|
395 |
public static String path () |
396 |
{ |
397 |
return path( new GregorianCalendar() ); |
398 |
} // path |
399 |
|
400 |
|
401 |
public Arc ( String base, String url, Sink fwd ) |
402 |
throws Exception |
403 |
{ |
404 |
_b = base; |
405 |
_u = url; |
406 |
_fwd = fwd; |
407 |
File b = new File(_b); |
408 |
if ( ! b.isDirectory() && ! b.mkdirs() ) |
409 |
throw new FileNotFoundException( _b ); |
410 |
} |
411 |
|
412 |
public String toString () { |
413 |
return "Arc "+_b+" "+_u; |
414 |
} |
415 |
|
416 |
public void put ( Message m ) |
417 |
throws Exception |
418 |
{ |
419 |
String mid = head( m, MESSAGEID, "<?>" ); |
420 |
System.err.println( _b+" += "+mid ); |
421 |
Date d = m.getSentDate(); |
422 |
if ( null == d ) |
423 |
d = m.getReceivedDate(); |
424 |
if ( null == d ) { |
425 |
System.err.println( "warning: no date found in "+mid ); |
426 |
d = new Date(); |
427 |
} |
428 |
String base = path( d ); |
429 |
String path = base; |
430 |
File f = new File( _b + path ); |
431 |
File dir = f.getParentFile(); |
432 |
if ( ! dir.isDirectory() && ! dir.mkdirs() ) |
433 |
throw new FileNotFoundException( dir.getAbsolutePath() ); |
434 |
for ( int i=0; ! f.createNewFile(); i++ ) |
435 |
f = new File( _b + (path = base + Integer.toString( i, 36 )) ); |
436 |
String name = f.getName(); |
437 |
// got unique path path |
438 |
System.out.println( "new message "+mid+" date "+d+" -> "+path ); |
439 |
MimeMessage mm = new MimeMessage( SES ); |
440 |
Enumeration e = m.getAllHeaders(); |
441 |
while ( e.hasMoreElements() ) { |
442 |
Header h = (Header)e.nextElement(); |
443 |
String n = h.getName().toLowerCase(); |
444 |
if ( OK == OKHDR.get(n) ) |
445 |
mm.addHeader( n, h.getValue() ); |
446 |
} |
447 |
mm.addHeader( CTYPE, TEXT_ISO ); |
448 |
mm.addHeader( CTRANSENC, "8bit" ); |
449 |
StringBuffer b = new StringBuffer( 4096 ); |
450 |
Stack s = new Stack(); |
451 |
s.push( m ); |
452 |
int i = 0; |
453 |
int totlines = 0; |
454 |
List binparts = new ArrayList( 32 ); |
455 |
while ( ! s.isEmpty() ) { |
456 |
Part p = (Part)s.pop(); |
457 |
String ct = oneline( p.getContentType() ); |
458 |
// ct = null == ct ? TEXT_PLAIN : ct.toLowerCase(); |
459 |
|
460 |
if ( p.isMimeType( MULT_ANY ) ) { |
461 |
Object content = p.getContent(); |
462 |
if ( ! (content instanceof Multipart) ) { |
463 |
// ignore |
464 |
System.err.println( "multipart type "+ct |
465 |
+" has class "+content.getClass().getName() ); |
466 |
mm.addHeader( COMMENTS, "dropped bad multipart "+ct ); |
467 |
} else { |
468 |
Multipart mu = (Multipart)content; |
469 |
int cnt = mu.getCount(); |
470 |
if ( cnt > 8 ) { |
471 |
System.err.println( "multipart with too many parts: "+cnt ); |
472 |
cnt = 8; |
473 |
} |
474 |
Part[] pu = new Part[cnt]; |
475 |
for ( int j=0; j<cnt; j++ ) |
476 |
pu[j] = mu.getBodyPart( j ); |
477 |
if ( p.isMimeType( MULT_ALT ) |
478 |
|| p.isMimeType( MULT_SIGN ) |
479 |
) { // alternatives suggested |
480 |
int select = -1; |
481 |
for ( int j=0; j<cnt; j++ ) // see wether we can decide |
482 |
if ( pu[j].isMimeType( TEXT_PLAIN ) ) { |
483 |
select = j; |
484 |
break; |
485 |
} |
486 |
if ( 0 <= select ) { |
487 |
for ( int j=0; j<cnt; j++ ) |
488 |
if ( select != j ) |
489 |
mm.addHeader( COMMENTS, "dropped alternative "+ |
490 |
oneline( pu[j].getContentType() ) + " for "+i ); |
491 |
if ( 0 != select ) |
492 |
pu[0] = pu[select]; |
493 |
cnt = 1; |
494 |
} |
495 |
} else if ( p.isMimeType( MULT_APPLE ) // apple ... |
496 |
&& 2 == cnt // ... double |
497 |
) { // kill ressource fork |
498 |
int j = 0; |
499 |
if ( pu[0].isMimeType( APPL_APPLE ) |
500 |
|| pu[j=1].isMimeType( APPL_APPLE ) |
501 |
) { |
502 |
if ( 0 == j ) |
503 |
pu[0] = pu[1]; |
504 |
mm.addHeader( COMMENTS, "dropped appledouble" ); |
505 |
cnt = 1; |
506 |
} |
507 |
} |
508 |
for ( int j=cnt; j-- > 0; ) // push parts backwards |
509 |
s.push( pu[j] ); |
510 |
} |
511 |
continue; |
512 |
} // multi |
513 |
|
514 |
i++; // about to create part i |
515 |
String part = path+'-'+i; |
516 |
|
517 |
// if ( ! p.isMimeType( TEXT_PLAIN ) ) { |
518 |
/* |
519 |
it's so awfully unreliable ... many RTFs go as APPL_WORD ... |
520 |
if ( p.isMimeType( TEXT_HTML ) ) |
521 |
ext = ".html"; |
522 |
else if ( p.isMimeType( APPL_WORD ) ) |
523 |
ext = ".doc"; |
524 |
else |
525 |
ext = ""; |
526 |
*/ |
527 |
OutputStream o = new FileOutputStream( _b+part ); |
528 |
p.getDataHandler().writeTo( o ); |
529 |
o.close(); |
530 |
// can we convert it ? |
531 |
String[] args = new String[] { "any2txt", "-v", name+'-'+i }; |
532 |
Process fix = Runtime.getRuntime().exec( args, null, dir ); |
533 |
BufferedReader err = new BufferedReader( new InputStreamReader( |
534 |
fix.getErrorStream() ) ); |
535 |
String line; |
536 |
while ( null != (line = err.readLine()) ) |
537 |
System.err.println( "any2txt:\t"+line ); |
538 |
err.close(); |
539 |
fix.waitFor(); |
540 |
int ret = fix.exitValue(); |
541 |
String ext = EMPTY; |
542 |
boolean havetext = 0 != (ret & 1) || 0 == ret; |
543 |
int type = ret & ~1; |
544 |
switch ( type ) { |
545 |
case 0: ext = ".txt"; break; |
546 |
case 2: ext = ".html"; break; |
547 |
case 4: ext = ".pdf"; break; |
548 |
case 6: ext = ".rtf"; break; |
549 |
case 8: ext = ".doc"; break; |
550 |
case 16: // mail -- reread and start over |
551 |
try { |
552 |
s.push( new MimeMessage( SES, new FileInputStream( _b+part ) ) ); |
553 |
// TODO: delete |
554 |
continue; |
555 |
} catch (Exception ee) { |
556 |
System.err.println( "could not reload mail "+mid+"["+i+"] "+ct |
557 |
+" from "+part ); |
558 |
ee.printStackTrace(); |
559 |
} |
560 |
ext = ".eml"; |
561 |
break; |
562 |
case 32: ext = ".gif"; break; |
563 |
case 34: ext = ".jpg"; break; |
564 |
case 36: ext = ".bmp"; break; |
565 |
case 38: ext = ".png"; break; |
566 |
case 40: ext = ".tiff"; break; |
567 |
} |
568 |
System.err.println( mid+"["+i+"] "+ct+" is "+ext+" ("+ret+")" ); |
569 |
|
570 |
if ( EMPTY != ext && 1 != ret ) // rename |
571 |
(new File(_b+part)).renameTo( new File(_b+part+ext) ); |
572 |
|
573 |
if ( 0 != type ) { |
574 |
binparts.add( name+'-'+i+ext ); |
575 |
// mm.addHeader( COMMENTS, "part "+i+" "+ct+" is "+part ); |
576 |
if ( ! havetext ) { |
577 |
if ( ! _zip ) { |
578 |
if ( 0 < totlines ) |
579 |
b.append( "\r\n---\r\n\r\n" ); |
580 |
b.append( "\r\nget part "+i+" at "+_u+part+ext+"\r\n" ); |
581 |
} |
582 |
totlines++; |
583 |
continue; |
584 |
} |
585 |
} |
586 |
// } |
587 |
|
588 |
// now _b+part.txt contains plaintext |
589 |
File plain = new File(_b+part+".txt"); |
590 |
BufferedReader br = new BufferedReader( |
591 |
new InputStreamReader( new FileInputStream( plain ) ) ); |
592 |
int lines = 0; |
593 |
int max = _maxlines - totlines; |
594 |
if ( max < _minlines ) |
595 |
max = _minlines; |
596 |
// String line; |
597 |
if ( 0 < totlines ) |
598 |
b.append( "\r\n---\r\n\r\n" ); |
599 |
while ( null != (line = br.readLine()) ) { |
600 |
b.append( line ).append( "\r\n" ); |
601 |
if ( max == ++lines ) { |
602 |
mm.addHeader( COMMENTS, "plaintext "+i+" continued at "+part ); |
603 |
b.append( "... read more: "+_u+part+".txt (" |
604 |
+(1 + plain.length()/1024)+" KB)\r\n" ); |
605 |
break; |
606 |
} |
607 |
} |
608 |
if ( 0 != type && !_zip ) |
609 |
b.append( "\r\nget original part "+i+" at "+_u+part+ext+"\r\n" ); |
610 |
totlines += lines; |
611 |
br.close(); |
612 |
} |
613 |
int nparts = binparts.size(); |
614 |
if ( _zip && 0 != nparts ) { |
615 |
String[] args = new String[3+nparts]; |
616 |
int a=0; |
617 |
args[a++] = "zip"; |
618 |
args[a++] = "-m"; // move |
619 |
args[a++] = name+".zip"; |
620 |
for ( int p = 0; p<nparts; p++ ) |
621 |
args[a++] = (String)binparts.get(p); |
622 |
Process zip = Runtime.getRuntime().exec( |
623 |
args, null, dir ); |
624 |
BufferedReader out = new BufferedReader( new InputStreamReader( |
625 |
zip.getInputStream() ) ); |
626 |
String line; |
627 |
while ( null != (line = out.readLine()) ) |
628 |
b.append( line+"\r\n" ); |
629 |
// System.err.println( "zip:\t"+line ); |
630 |
out.close(); |
631 |
zip.waitFor(); |
632 |
int ret = zip.exitValue(); |
633 |
File zipped = new File(_b+path+".zip"); |
634 |
if ( 0 != ret ) |
635 |
System.err.println( "zip exited "+ret ); |
636 |
else if ( ! zipped.exists() ) |
637 |
System.err.println( "no zipfile "+zipped ); |
638 |
else |
639 |
b.append( "\r\nget original parts at "+_u+path+".zip (" |
640 |
+(1 + zipped.length()/1024)+" KB)\r\n" ); |
641 |
} |
642 |
mm.setContent( b.toString(), TEXT_ISO ); |
643 |
OutputStream o = new FileOutputStream(f); |
644 |
mm.writeTo( o ); |
645 |
o.close(); |
646 |
f.renameTo( new File( f.getPath()+".mail" ) ); |
647 |
if ( null != _fwd ) |
648 |
_fwd.put( mm ); |
649 |
} |
650 |
|
651 |
public void put ( Message[] m ) |
652 |
throws Exception |
653 |
{ |
654 |
Mail.put( this, m ); |
655 |
} |
656 |
} // class Arc |
657 |
|
658 |
|
659 |
public static class Smtp implements Sink { |
660 |
|
661 |
Transport _t; |
662 |
Address[] _a; |
663 |
boolean _conn; |
664 |
|
665 |
public Smtp ( Session s, Address[] a ) throws Exception { |
666 |
_t = s.getTransport( s.getProvider("smtp") ); |
667 |
_a = a; |
668 |
} |
669 |
|
670 |
public Smtp ( Address[] a ) throws Exception { |
671 |
this( SES, a ); |
672 |
} |
673 |
|
674 |
public Smtp ( String a ) throws Exception { |
675 |
this( SES, new Address[] { new InternetAddress(a) } ); |
676 |
} |
677 |
|
678 |
/** connect. return true, iff we weren't already connected. */ |
679 |
public boolean connect () throws Exception { |
680 |
if ( _conn ) |
681 |
return false; |
682 |
_t.connect(); |
683 |
return _conn = true; |
684 |
} |
685 |
|
686 |
public void close () throws Exception { |
687 |
if ( _conn ) { |
688 |
_t.close(); |
689 |
_conn = false; |
690 |
} |
691 |
} |
692 |
|
693 |
public void put ( Message m ) |
694 |
throws Exception |
695 |
{ |
696 |
boolean nconn = connect(); |
697 |
_t.sendMessage( m, null != _a ? _a : m.getAllRecipients() ); |
698 |
if ( nconn ) close(); |
699 |
} |
700 |
|
701 |
public void put ( Message[] m ) |
702 |
throws Exception |
703 |
{ |
704 |
boolean nconn = connect(); |
705 |
Mail.put( this, m ); |
706 |
if ( nconn ) close(); |
707 |
} |
708 |
} // class Smtp |
709 |
|
710 |
|
711 |
public static class Cmd implements Sink { |
712 |
|
713 |
String _cmd; |
714 |
|
715 |
public Cmd ( String cmd ) { |
716 |
_cmd = cmd; |
717 |
} |
718 |
|
719 |
public void put ( Message m ) |
720 |
throws Exception |
721 |
{ |
722 |
Process run = Runtime.getRuntime().exec( _cmd ); |
723 |
OutputStream o = run.getOutputStream(); |
724 |
m.writeTo( o ); |
725 |
o.close(); |
726 |
BufferedReader err = new BufferedReader( new InputStreamReader( |
727 |
run.getErrorStream() ) ); |
728 |
String line; |
729 |
while ( null != (line = err.readLine()) ) |
730 |
System.err.println( _cmd+":\t"+line ); |
731 |
err.close(); |
732 |
run.waitFor(); |
733 |
int ret = run.exitValue(); |
734 |
if ( 0 != ret ) |
735 |
System.err.println( "Cmd '"+_cmd+"' exited "+ret ); |
736 |
} |
737 |
|
738 |
public void put ( Message[] m ) |
739 |
throws Exception |
740 |
{ |
741 |
Mail.put( this, m ); |
742 |
} |
743 |
} // class Cmd |
744 |
|
745 |
|
746 |
public static void main ( String[] args ) |
747 |
throws Exception |
748 |
{ |
749 |
String host = "localhost"; |
750 |
int port = 110; |
751 |
String user = "test"; |
752 |
String pass = "test"; |
753 |
String sodir = "/tmp/test"; |
754 |
String sidir = "/tmp/test"; |
755 |
String url = "http://openisis.org/archive"; |
756 |
int a = 0; |
757 |
Source so = null; |
758 |
Sink si = null; |
759 |
Sink fwd = null; |
760 |
char source = 'd'; |
761 |
char sink = 'd'; |
762 |
char task = 0; |
763 |
int n = 0; |
764 |
|
765 |
while ( a<args.length ) { |
766 |
String arg = args[a++]; |
767 |
if ( "-h".equals( arg ) ) |
768 |
host = args[a++]; |
769 |
else if ( "-o".equals( arg ) ) |
770 |
port = Integer.parseInt( args[a++] ); |
771 |
else if ( "-u".equals( arg ) ) |
772 |
user = args[a++]; |
773 |
else if ( "-p".equals( arg ) ) |
774 |
pass = args[a++]; |
775 |
else if ( "-pop".equals( arg ) ) |
776 |
source = 'p'; |
777 |
else if ( "-url".equals( arg ) ) // arc |
778 |
url = args[a++]; |
779 |
else if ( "-fwd".equals( arg ) ) // fwd by smtp |
780 |
fwd = new Smtp( args[a++] ); |
781 |
else if ( "-fwdcmd".equals( arg ) ) // fwd by command |
782 |
fwd = new Cmd( args[a++] ); |
783 |
else if ( "-dir".equals( arg ) ) { |
784 |
source = 'd'; |
785 |
sodir = args[a++]; |
786 |
} else if ( "-todir".equals( arg ) ) { |
787 |
sink = 'd'; |
788 |
sidir = args[a++]; |
789 |
} else if ( "-toarc".equals( arg ) ) { |
790 |
sink = 'a'; |
791 |
sidir = args[a++]; |
792 |
} else if ( "-move".equals( arg ) ) |
793 |
task = 'v'; |
794 |
else |
795 |
throw new IllegalArgumentException( arg ); |
796 |
} |
797 |
|
798 |
switch ( source ) { |
799 |
case 'p': |
800 |
so = new Pop( host, port, user, pass, 8 ); |
801 |
break; |
802 |
default: // 'd' |
803 |
so = new Dir( sodir ); |
804 |
} |
805 |
switch ( sink ) { |
806 |
case 'a': |
807 |
si = new Arc( sidir, url, fwd ); |
808 |
break; |
809 |
default: // 'd' |
810 |
si = new Dir( sidir ); |
811 |
} |
812 |
|
813 |
switch ( task ) { |
814 |
case 'v': // -move |
815 |
n = move( si, so ); |
816 |
System.err.println( "moved "+n+" messages from "+so+" to "+si ); |
817 |
break; |
818 |
} |
819 |
} |
820 |
} // Mail |