1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/common/protocol.cpp
3// Purpose:     Implement protocol base class
4// Author:      Guilhem Lavaux
5// Modified by:
6// Created:     07/07/1997
7// RCS-ID:      $Id: protocol.cpp 40943 2006-08-31 19:31:43Z ABX $
8// Copyright:   (c) 1997, 1998 Guilhem Lavaux
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16    #pragma hdrstop
17#endif
18
19#if wxUSE_PROTOCOL
20
21#include "wx/protocol/protocol.h"
22
23#ifndef WX_PRECOMP
24    #include "wx/module.h"
25#endif
26
27#include "wx/url.h"
28
29#include <stdlib.h>
30
31/////////////////////////////////////////////////////////////////
32// wxProtoInfo
33/////////////////////////////////////////////////////////////////
34
35/*
36 * --------------------------------------------------------------
37 * --------- wxProtoInfo CONSTRUCTOR ----------------------------
38 * --------------------------------------------------------------
39 */
40
41wxProtoInfo::wxProtoInfo(const wxChar *name, const wxChar *serv,
42                         const bool need_host1, wxClassInfo *info)
43           : m_protoname(name),
44             m_servname(serv)
45{
46    m_cinfo = info;
47    m_needhost = need_host1;
48#if wxUSE_URL
49    next = wxURL::ms_protocols;
50    wxURL::ms_protocols = this;
51#else
52    next = NULL;
53#endif
54}
55
56/////////////////////////////////////////////////////////////////
57// wxProtocol ///////////////////////////////////////////////////
58/////////////////////////////////////////////////////////////////
59
60#if wxUSE_SOCKETS
61IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxSocketClient)
62#else
63IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxObject)
64#endif
65
66wxProtocol::wxProtocol()
67#if wxUSE_SOCKETS
68 : wxSocketClient()
69#endif
70{
71}
72
73#if wxUSE_SOCKETS
74bool wxProtocol::Reconnect()
75{
76    wxIPV4address addr;
77
78    if (!GetPeer(addr))
79    {
80        Close();
81        return false;
82    }
83
84    if (!Close())
85        return false;
86
87    if (!Connect(addr))
88        return false;
89
90    return true;
91}
92
93// ----------------------------------------------------------------------------
94// Read a line from socket
95// ----------------------------------------------------------------------------
96
97/* static */
98wxProtocolError wxProtocol::ReadLine(wxSocketBase *sock, wxString& result)
99{
100    static const int LINE_BUF = 4095;
101
102    result.clear();
103
104    wxCharBuffer buf(LINE_BUF);
105    char *pBuf = buf.data();
106    while ( sock->WaitForRead() )
107    {
108        // peek at the socket to see if there is a CRLF
109        sock->Peek(pBuf, LINE_BUF);
110
111        size_t nRead = sock->LastCount();
112        if ( !nRead && sock->Error() )
113            return wxPROTO_NETERR;
114
115        // look for "\r\n" paying attention to a special case: "\r\n" could
116        // have been split by buffer boundary, so check also for \r at the end
117        // of the last chunk and \n at the beginning of this one
118        pBuf[nRead] = '\0';
119        const char *eol = strchr(pBuf, '\n');
120
121        // if we found '\n', is there a '\r' as well?
122        if ( eol )
123        {
124            if ( eol == pBuf )
125            {
126                // check for case of "\r\n" being split
127                if ( result.empty() || result.Last() != _T('\r') )
128                {
129                    // ignore the stray '\n'
130                    eol = NULL;
131                }
132                //else: ok, got real EOL
133
134                // read just this '\n' and restart
135                nRead = 1;
136            }
137            else // '\n' in the middle of the buffer
138            {
139                // in any case, read everything up to and including '\n'
140                nRead = eol - pBuf + 1;
141
142                if ( eol[-1] != '\r' )
143                {
144                    // as above, simply ignore stray '\n'
145                    eol = NULL;
146                }
147            }
148        }
149
150        sock->Read(pBuf, nRead);
151        if ( sock->LastCount() != nRead )
152            return wxPROTO_NETERR;
153
154        pBuf[nRead] = '\0';
155        result += wxString::FromAscii(pBuf);
156
157        if ( eol )
158        {
159            // remove trailing "\r\n"
160            result.RemoveLast(2);
161
162            return wxPROTO_NOERR;
163        }
164    }
165
166    return wxPROTO_NETERR;
167}
168
169wxProtocolError wxProtocol::ReadLine(wxString& result)
170{
171    return ReadLine(this, result);
172}
173
174// old function which only chops '\n' and not '\r\n'
175wxProtocolError GetLine(wxSocketBase *sock, wxString& result)
176{
177#define PROTO_BSIZE 2048
178    size_t avail, size;
179    char tmp_buf[PROTO_BSIZE], tmp_str[PROTO_BSIZE];
180    char *ret;
181    bool found;
182
183    avail = sock->Read(tmp_buf, PROTO_BSIZE).LastCount();
184    if (sock->Error() || avail == 0)
185        return wxPROTO_NETERR;
186
187    memcpy(tmp_str, tmp_buf, avail);
188
189    // Not implemented on all systems
190    // ret = (char *)memccpy(tmp_str, tmp_buf, '\n', avail);
191    found = false;
192    for (ret=tmp_str;ret < (tmp_str+avail); ret++)
193        if (*ret == '\n')
194        {
195            found = true;
196            break;
197        }
198
199    if (!found)
200        return wxPROTO_PROTERR;
201
202    *ret = 0;
203
204    result = wxString::FromAscii( tmp_str );
205    result = result.Left(result.length()-1);
206
207    size = ret-tmp_str+1;
208    sock->Unread(&tmp_buf[size], avail-size);
209
210    return wxPROTO_NOERR;
211#undef PROTO_BSIZE
212}
213#endif // wxUSE_SOCKETS
214
215#endif // wxUSE_PROTOCOL
216