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