1 /* -*- Mode: c++; -*- */
2 /*  --------------------------------------------------------------------
3  *  Filename:
4  *    bincimap-up.cc
5  *
6  *  Description:
7  *    Implementation of the preauthenticated bincimap stub
8  *
9  *  Authors:
10  *    Andreas Aardal Hanssen <andreas-binc curly bincimap spot org>
11  *
12  *  Bugs:
13  *
14  *  ChangeLog:
15  *
16  *  --------------------------------------------------------------------
17  *  Copyright 2002-2005 Andreas Aardal Hanssen
18  *
19  *  This program is free software; you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License as published by
21  *  the Free Software Foundation; either version 2 of the License, or
22  *  (at your option) any later version.
23  *
24  *  This program is distributed in the hope that it will be useful,
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *  GNU General Public License for more details.
28  *
29  *  You should have received a copy of the GNU General Public License
30  *  along with this program; if not, write to the Free Software
31  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
32  *  --------------------------------------------------------------------
33  */
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 
38 #include <string>
39 
40 #include "broker.h"
41 #include "recursivedescent.h"
42 #include "io.h"
43 #ifdef WITH_SSL
44 #include "io-ssl.h"
45 #endif
46 #include "operators.h"
47 #include "session.h"
48 
49 using namespace ::std;
50 using namespace Binc;
51 
52 namespace Binc {
53   bool showGreeting(void);
54 }
55 
56 //------------------------------------------------------------------------
main(int argc,char * argv[])57 int main(int argc, char *argv[])
58 {
59   Session &session = Session::getInstance();
60   if (!session.initialize(argc, argv)) {
61     if (session.getLastError() != "") {
62       IO &logger = IOFactory::getInstance().get(2);
63       logger << "error initializing Binc IMAP: " << session.getLastError()
64 	     << endl;
65       logger.flushContent();
66     }
67     return 111;
68   }
69 
70   IO &com = IOFactory::getInstance().get(1);
71   IO &logger = IOFactory::getInstance().get(2);
72 
73   logger << "connection from " << session.getIP() << endl;
74 
75   // Show standard greeting
76   showGreeting();
77   bool recovery = false;
78   bool timedout = false;
79   bool disconnect = false;
80   bool abrt = false;
81 
82   // Read commands and run functions
83   do {
84     com.enableInputLimit();
85 
86     // recover from syntax error. There will be trash in the input
87     // buffer. We need to flush everything until we see an LF.
88     if (recovery) {
89       for (;;) {
90 	int c = com.readChar(session.timeout());
91 	if (c == '\n') break;
92 	if (c == -1) {
93 	  disconnect = true;
94 	  abrt = true;
95 	  break;
96 	} else if (c == -2) {
97 	  com << "* BYE Timeout after " << session.timeout()
98 	      << " seconds of inactivity." << endl;
99 	  timedout = true;
100 	  abrt = true;
101 	  break;
102 	}
103       }
104 
105       if (abrt)
106 	break;
107     }
108 
109     Request request;
110     recovery = false;
111 
112     BrokerFactory &brokerFactory = BrokerFactory::getInstance();
113     Broker *broker = brokerFactory.getBroker(session.getState());
114     if (!broker) {
115       // will never happen
116     }
117 
118     com.flushContent();
119     com.noFlushOnEndl();
120 
121     switch (broker->parseStub(request)) {
122     case Operator::TIMEOUT:
123       com << "* BYE Timeout after " << session.timeout()
124 	  << " seconds of inactivity." << endl;
125       timedout = true;
126       abrt = true;
127       break;
128     case Operator::REJECT:
129       com << "* NO " << session.getLastError() << endl;
130       recovery = true;
131       continue;
132     case Operator::ERROR:
133       com << "* BAD " << session.getLastError() << endl;
134       recovery = true;
135       continue;
136     default:
137       break;
138     }
139 
140     if (abrt)
141       break;
142 
143     Operator *o = broker->get(request.getName());
144     if (!o) {
145       com << request.getTag() << " NO The command \""
146 	  << (request.getUidMode() ? "UID " : "")
147 	  << request.getName()
148 	  << "\" is unsupported in this state. "
149 	  << "Please authenticate." << endl;
150       recovery = true;
151       continue;
152     }
153 
154     switch (o->parse(request)) {
155     case Operator::TIMEOUT:
156       com << "* BYE Timeout after " << session.timeout()
157 	  << " seconds of inactivity." << endl;
158       timedout = true;
159       abrt = true;
160       break;
161     case Operator::REJECT:
162       com << "* NO " << session.getLastError() << endl;
163       recovery = true;
164       continue;
165     case Operator::ERROR:
166       com << "* BAD " << session.getLastError() << endl;
167       recovery = true;
168       continue;
169     default:
170       break;
171     }
172 
173     switch (o->process(*session.getDepot(), request)) {
174     case Operator::OK:
175       com << request.getTag() << " OK " << request.getName()
176 	  << " completed" << endl;
177       break;
178     case Operator::NO:
179       com << request.getTag() << " NO " << session.getResponseCode()
180           << request.getName() << " failed: " << session.getLastError() << endl;
181       session.clearResponseCode();
182       break;
183     case Operator::BAD:
184       com << request.getTag() << " BAD " << request.getName()
185 	  << " failed: " << session.getLastError() << endl;
186       recovery = true;
187       break;
188     case Operator::NOTHING:
189       break;
190     case Operator::ABORT:
191       session.setState(Session::LOGOUT);
192       abrt = true;
193       break;
194     }
195 
196     if (abrt)
197       break;
198   } while (session.getState() != Session::LOGOUT);
199 
200   logger << "shutting down ";
201   if (timedout)
202     logger << "(timeout " + toString(session.timeout()) + "s) ";
203   else if (disconnect)
204     logger << "(" << com.getLastError() << ") ";
205 
206   logger << "- read:"
207 	 << session.getReadBytes()
208 	 << " bytes, wrote:" << session.getWriteBytes()
209 	 << " bytes." << endl;
210 
211   com.flushContent();
212 }
213