1 // Copyright 2009 The Archiveopteryx Developers <info@aox.org>
2
3 #include "queue.h"
4
5 #include "query.h"
6 #include "recipient.h"
7 #include "transaction.h"
8
9 #include <stdio.h>
10
11
12 static AoxFactory<ShowQueue>
13 f( "show", "queue", "Display the outgoing mail queue.",
14 " Synopsis: aox show queue\n\n"
15 " Displays a list of mail queued for delivery to a smarthost.\n" );
16
17
18 /*! \class ShowQueue queue.h
19 This class handles the "aox show queue" command.
20 */
21
ShowQueue(EStringList * args)22 ShowQueue::ShowQueue( EStringList * args )
23 : AoxCommand( args ), q( 0 ), qr( 0 )
24 {
25 }
26
27
execute()28 void ShowQueue::execute()
29 {
30 if ( !q ) {
31 parseOptions();
32 end();
33
34 database();
35
36 EString s(
37 "select d.id, d.message, "
38 "(a.localpart||'@'||a.domain)::text as sender, "
39 "to_char(d.injected_at, 'YYYY-MM-DD HH24:MI:SS') as submitted, "
40 "to_char(max(dr.last_attempt), 'YYYY-MM-DD HH24:MI:SS') as tried, "
41 "(extract(epoch from d.expires_at)-extract(epoch from current_timestamp))::bigint as expires_in "
42 "from deliveries d join addresses a on (d.sender=a.id) "
43 "join delivery_recipients dr on (d.id=dr.delivery) "
44 );
45 if ( !opt( 'a' ) )
46 s.append( "where dr.action=$1 or dr.action=$2 " );
47 s.append( "group by d.id, d.message, "
48 "a.domain, a.localpart, d.injected_at, d.expires_at "
49 "order by submitted, tried, sender" );
50
51 q = new Query( s, this );
52 if ( !opt( 'a' ) ) {
53 q->bind( 1, Recipient::Unknown );
54 q->bind( 2, Recipient::Delayed );
55 }
56 q->execute();
57 }
58
59 while ( qr || q->hasResults() ) {
60 if ( !qr ) {
61 Row * r = q->nextRow();
62 uint delivery = r->getInt( "id" );
63 uint message = r->getInt( "message" );
64 EString sender( r->getEString( "sender" ) );
65
66 if ( sender == "@" )
67 sender = "<>";
68
69 printf( "%d: Message %d from %s (submitted %s)\n",
70 delivery, message, sender.cstr(),
71 r->getEString( "submitted" ).cstr() );
72 bool nl = false;
73 if ( !r->isNull( "tried" ) ) {
74 printf( "\t(last tried %s",
75 r->getEString( "tried" ).cstr() );
76 nl = true;
77 }
78 int64 expires = r->getBigint( "expires_in" );
79 if ( expires > 0 && expires < 604800 ) {
80 printf( "%sexpires in %d:%02d:%02d",
81 nl ? ", " : "\t(",
82 (int)expires / 3600, ( (int)expires / 60 ) % 60,
83 (int)expires % 60 );
84 nl = true;
85 }
86 if ( nl )
87 printf( ")\n" );
88
89 EString s(
90 "select action, status, "
91 "a.domain::text as domain, a.localpart::text, "
92 "(a.localpart||'@'||a.domain)::text as recipient "
93 "from delivery_recipients dr join addresses a "
94 "on (dr.recipient=a.id) where dr.delivery=$1 "
95 "order by dr.action, a.domain, a.localpart"
96 );
97 qr = new Query( s, this );
98 qr->bind( 1, delivery );
99 qr->execute();
100 }
101
102 while ( qr->hasResults() ) {
103 Row * r = qr->nextRow();
104
105 EString recipient( r->getEString( "recipient" ) );
106 printf( "\t%s", recipient.cstr() );
107
108 uint action = r->getInt( "action" );
109 switch ( action ) {
110 case 0:
111 printf( " (not tried yet" );
112 break;
113 case 1:
114 printf( " (failed" );
115 break;
116 case 2:
117 printf( " (delayed" );
118 break;
119 case 3:
120 printf( " (delivered" );
121 break;
122 case 4:
123 printf( " (relayed" );
124 break;
125 case 5:
126 printf( " (expanded" );
127 break;
128 }
129
130 EString status;
131 if ( !r->isNull( "status" ) )
132 status = r->getEString( "status" );
133 if ( opt( 'v' ) && !status.isEmpty() )
134 printf( ": status is %s", status.cstr() );
135 printf( ")\n" );
136 }
137
138 if ( !qr->done() )
139 return;
140
141 if ( q->hasResults() )
142 printf( "\n" );
143
144 qr = 0;
145 }
146
147 if ( !q->done() )
148 return;
149
150 finish();
151 }
152
153
154 static AoxFactory<FlushQueue>
155 g( "flush", "queue", "Trigger delivery attempts for all spooled mail.",
156 " Synopsis: aox flush queue\n\n"
157 " Instructs the running server to try to deliver all spooled mail"
158 " to the smarthost.\n" );
159
160
161 /*! \class FlushQueue queue.h
162 This class handles the "aox flush queue" command.
163 */
164
FlushQueue(EStringList * args)165 FlushQueue::FlushQueue( EStringList * args )
166 : AoxCommand( args ), t( 0 )
167 {
168 }
169
170
execute()171 void FlushQueue::execute()
172 {
173 if ( !t ) {
174 parseOptions();
175 end();
176
177 database();
178 t = new Transaction( this );
179 t->enqueue( new Query( "update delivery_recipients "
180 "set last_attempt=null "
181 "where action=2", 0 ) );
182 t->enqueue( new Query( "notify deliveries_updated", 0 ) );
183 t->commit();
184 }
185
186 if ( !t->done() )
187 return;
188
189 finish();
190 }
191