Switch to unified view

a b/src/bincimapmime/iodevice.h
1
/*-*-mode:c++-*-*/
2
/*  --------------------------------------------------------------------
3
 *  Filename:
4
 *    src/iodevice.h
5
 *  
6
 *  Description:
7
 *    Declaration of the IODevice class.
8
 *  --------------------------------------------------------------------
9
 *  Copyright 2002, 2003 Andreas Aardal Hanssen
10
 *
11
 *  This program is free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  This program is distributed in the hope that it will be useful,
17
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 *  GNU General Public License for more details.
20
 *
21
 *  You should have received a copy of the GNU General Public License
22
 *  along with this program; if not, write to the Free Software
23
 *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
24
 *  --------------------------------------------------------------------
25
 */
26
#ifndef iodevice_h_included
27
#define iodevice_h_included
28
#ifdef HAVE_CONFIG_H
29
#include <config.h>
30
#endif
31
32
#include "convert.h" // BincStream
33
#include <string>
34
#include <unistd.h> // ::write
35
36
namespace Binc {
37
  /*!
38
    \class IODevice
39
    \brief The IODevice class provides a framework for reading and
40
    writing to device.
41
42
    Implement new devices by inheriting this class and overloading all
43
    virtual methods.
44
45
    service() returns the service that the specific device is used
46
    for. Two values are "log" and "client".
47
48
    \sa IOFactory, MultilogDevice, SyslogDevice, StdIODevice, SSLDevice
49
  */
50
  class IODevice {
51
  public:
52
    /*!
53
      Standard options for an IODevice.
54
    */
55
    enum Flags {
56
      None = 0,
57
      FlushesOnEndl = 1 << 0,
58
      HasInputLimit = 1 << 1,
59
      HasOutputLimit = 1 << 2,
60
      IsEnabled = 1 << 3,
61
      HasTimeout = 1 << 4
62
    };
63
64
    /*!
65
      Errors from when an operation returned false.
66
    */
67
    enum Error {
68
      Unknown,
69
      Timeout
70
    };
71
72
    /*!
73
      Constructs an invalid IODevice.      
74
75
      Instances of IODevice perform no operations, and all boolean
76
      functions always return false. This constructor is only useful
77
      if called from a subclass that reimplements all virtual methods.
78
    */
79
    IODevice(int f = 0);
80
81
    /*!
82
      Destructs an IODevice; does nothing.
83
    */
84
    virtual ~IODevice(void);
85
86
    /*!
87
      Clears all data in the input and output buffers.
88
    */
89
    void clear(void);
90
91
    /*!
92
      Sets one or more flags.
93
      \param f A bitwise OR of flags from the Flags enum.
94
    */
95
    void setFlags(unsigned int f);
96
97
    /*!
98
      Clears one or more flags.
99
      \param f A bitwise OR of flags from the Flags enum.
100
    */
101
    void clearFlags(unsigned int f);
102
103
    /*!
104
      Sets the maximum allowed input buffer size. If this size is
105
      non-zero and exceeded, reading from the device will fail. This
106
      functionality is used to prevent clients from forcing this class
107
      to consume so much memory that the program crashes.
108
109
      Setting the max input buffer size to 0 disables the input size
110
      limit.
111
112
      \param max The maximum input buffer size in bytes.
113
    */
114
    void setMaxInputBufferSize(unsigned int max);
115
116
    /*!
117
      Sets the maximum allowed output buffer size. If this size is
118
      non-zero and exceeded, flush() is called implicitly.
119
120
      Setting the max output buffer size to 0 disables the output size
121
      limit. This is generally discouraged.
122
123
      As a contrast to setMaxInputBufferSize(), this function is used
124
      to bundle up consequent write calls, allowing more efficient use
125
      of the underlying device as larger blocks of data are written at
126
      a time.
127
128
      \param max The maximum output buffer size in bytes.
129
    */
130
    void setMaxOutputBufferSize(unsigned int max);
131
132
    /*!
133
      Sets the device's internal timeout in seconds. This timeout is
134
      used both when waiting for data to read and for waiting for the
135
      ability to write.
136
137
      If this timeout is exceeded, the read or write function that
138
      triggered the timeout will fail.
139
140
      Setting the timeout to 0 disables the timeout.
141
142
      \param t The timeout in seconds.
143
      \sa getTimeout()
144
    */
145
    void setTimeout(unsigned int t);
146
147
    /*!
148
      Returns the timeout in seconds, or 0 if there is no timeout.
149
150
      \sa setTimeout()
151
    */
152
    unsigned int getTimeout(void) const;
153
154
    /*!
155
      Sets the output level for the following write operations on this
156
      device.
157
158
      The output level is a number which gives the following write
159
      operations a priority. You can use setOutputLevelLimit() to
160
      filter the write operations valid for different operating modes.
161
      This enables you to have certain write operations ignored.
162
163
      For instance, if the output level is set to 0, then "Hello" is
164
      written, and the output level is set to 1, followed by writing
165
      "Daisy", the output level limit value will decive wether only
166
      "Hello" is written, or if also "Daisy" is written.
167
168
      A low value of the level gives higher priority, and a high level
169
      will give low priority. The default value is 0, and write
170
      operations that are done with output level 0 are never ignored.
171
172
      \param level The output level
173
      \sa getOutputLevel(), setOutputLevelLimit()
174
    */
175
    void setOutputLevel(unsigned int level);
176
177
    /*!
178
      Returns the current output level.
179
180
      \sa setOutputLevel()
181
    */
182
    unsigned int getOutputLevel(void) const;
183
184
    /*!
185
      Sets the current output level limit. Write operations with a
186
      level higher than the output level limit are ignored.
187
188
      \param level The output level limit
189
      \sa setOutputLevel()
190
    */
191
    void setOutputLevelLimit(unsigned int level);
192
193
    /*!
194
      Returns the current output level limit.
195
196
      \sa setOutputLevelLimit()
197
    */
198
    unsigned int getOutputLevelLimit(void) const;
199
200
    /*!
201
      Returns the number of bytes that have been read from this device
202
      since it was created.
203
    */
204
    unsigned int getReadCount(void) const;
205
206
    /*!
207
      Returns the number of bytes that have been written to this
208
      device since it was created.
209
    */
210
    unsigned int getWriteCount(void) const;
211
212
    void enableProtocolDumping(void);
213
214
    /*!
215
      Writes data to the device. Depending on the value of the max
216
      output buffer size, the data may not be written immediately.
217
218
      \sa setMaxOutputBufferSize()
219
    */
220
    template <class T> IODevice &operator <<(const T &source);
221
222
    /*!
223
      Writes data to the device. This function specializes on standard
224
      ostream derivates, such as std::endl.
225
     */
226
    IODevice &operator <<(std::ostream &(*source)(std::ostream &));
227
228
    /*!
229
      Returns true if data can be read from the device; otherwise
230
      returns false.
231
    */
232
    virtual bool canRead(void) const;
233
234
    /*!
235
      Reads data from the device, and stores this in a string. Returns
236
      true on success; otherwise returns false.
237
      
238
      \param dest The incoming data is stored in this string.
239
      \param max No more than this number of bytes is read from the
240
      device.
241
    */
242
    bool readStr(std::string *dest, unsigned int max = 0);
243
244
    /*!
245
      Reads exactly one byte from the device and stores this in a
246
      char. Returns true on success; otherwise returns false.
247
248
      \param dest The incoming byte is stored in this char.
249
    */
250
    bool readChar(char *dest = 0);
251
252
    /*!
253
      FIXME: add docs
254
    */
255
    void unreadChar(char c);
256
257
    /*!
258
      FIXME: add docs
259
    */
260
    void unreadStr(const std::string &s);
261
262
    /*!
263
      Reads characters from the device, until and including one
264
      certain character is found. All read characters are discarded.
265
266
      This function can be used to skip to the beginning of a line,
267
      with the terminating character being '\n'.
268
269
      \param The certain character.
270
    */
271
    bool skipTo(char c);
272
273
    /*!
274
      Flushes the output buffer. Writes all data in the output buffer
275
      to the device.
276
    */
277
    bool flush(void);
278
279
    /*!
280
      Returns the type of error that most recently occurred.
281
    */
282
    Error getLastError(void) const;
283
284
    /*!
285
      Returns a human readable description of the error that most
286
      recently occurred. If no known error has occurred, this method
287
      returns "Unknown error".
288
    */
289
    std::string getLastErrorString(void) const;
290
291
    /*!
292
      Returns the type of service provided by this device. Two valid
293
      return values are "client" and "log".
294
    */
295
    virtual std::string service(void) const;
296
    
297
  protected:
298
    /*!
299
      Waits until data can be written to the device. If the timeout is
300
      0, this function waits indefinitely. Otherwise, it waits until
301
      the timeout has expired.
302
303
      If this function returns true, data can be written to the
304
      device; otherwise, getLastError() must be checked to determine
305
      whether a timeout occurred or whether an error with the device
306
      prevents further writing.
307
    */
308
    virtual bool waitForWrite(void) const;
309
310
    /*!
311
      Waits until data can be read from the device.
312
313
      \sa waitForWrite()
314
    */
315
    virtual bool waitForRead(void) const;
316
317
    /*!
318
      Types of results from a write. 
319
    */
320
    enum WriteResult {
321
      WriteWait = 0,
322
      WriteDone = 1 << 0,
323
      WriteError = 1 << 1
324
    };
325
326
    /*!
327
      Writes as much data as possible to the device. If some but not
328
      all data was written, returns WriteWait. If all data was
329
      written, returns WriteDone.  If an error occurred, returns
330
      WriteError.
331
    */
332
    virtual WriteResult write(void);
333
334
    /*!
335
      Reads data from the device, and stores it in the input buffer.
336
      Returns true on success; otherwise returns false.
337
      
338
      This method will fail if there is no more data available, if a
339
      timeout occurred or if an error with the device prevents more
340
      data from being read.
341
342
      The number of bytes read from the device is undefined.
343
    */
344
    virtual bool fillInputBuffer(void);
345
346
    BincStream inputBuffer;
347
    BincStream outputBuffer;
348
349
  protected:
350
    unsigned int flags;
351
    unsigned int maxInputBufferSize;
352
    unsigned int maxOutputBufferSize;
353
354
    unsigned int timeout;
355
356
    unsigned int readCount;
357
    unsigned int writeCount;
358
359
    unsigned int outputLevel;
360
    unsigned int outputLevelLimit;
361
362
    Error error;
363
    std::string errorString;
364
365
    int dumpfd;
366
  };
367
368
  //----------------------------------------------------------------------
369
  template <class T> IODevice &IODevice::operator <<(const T &source)
370
  {
371
    if ((flags & IsEnabled) && outputLevel <= outputLevelLimit) {
372
      outputBuffer << source;
373
374
      if (dumpfd) {
375
  BincStream ss;
376
  ss << source;
377
  ::write(dumpfd, ss.str().c_str(), ss.getSize());
378
      }
379
380
      if (flags & HasInputLimit)
381
  if (outputBuffer.getSize() > maxOutputBufferSize)
382
    flush();
383
    }
384
385
    return *this;
386
  }
387
}
388
389
#endif