0
|
1 /*
|
|
2 protocol.c
|
|
3
|
10
|
4 $Id: protocol.c 16 2000-04-11 06:50:16Z enz $
|
0
|
5 */
|
|
6
|
|
7 #include <ctype.h>
|
|
8 #include <netdb.h>
|
|
9 #include <sys/types.h>
|
|
10 #include <sys/utsname.h>
|
|
11 #include "common.h"
|
|
12 #include "dynamicstring.h"
|
|
13 #include "log.h"
|
|
14 #include "over.h"
|
|
15 #include "util.h"
|
|
16
|
|
17 Bool
|
|
18 Prt_getLn( Str line, FILE *f )
|
|
19 {
|
|
20 size_t len;
|
|
21
|
|
22 /*
|
|
23 We also accept lines ending with "\n" instead of "\r\n", some
|
|
24 clients wrongly send such lines.
|
|
25 */
|
|
26 if ( ! fgets( line, MAXCHAR, f ) )
|
|
27 {
|
|
28 Log_dbg( "Prt_getLine failed" );
|
|
29 return FALSE;
|
|
30 }
|
|
31 len = strlen( line );
|
|
32 if ( line[ len - 1 ] == '\n' )
|
|
33 {
|
|
34 line[ len - 1 ] = '\0';
|
|
35 if ( line[ len - 2 ] == '\r' )
|
|
36 line[ len - 2 ] = '\0';
|
|
37 }
|
|
38 Log_dbg( "[R] %s", line );
|
|
39 return TRUE;
|
|
40 }
|
|
41
|
|
42 Bool
|
|
43 Prt_getTxtLn( Str line, Bool *err, FILE *f )
|
|
44 {
|
|
45 Str buf;
|
|
46
|
|
47 if ( ! Prt_getLn( buf, f ) )
|
|
48 {
|
|
49 Log_err( "Cannot get text line" );
|
|
50 *err = TRUE;
|
|
51 return FALSE;
|
|
52 }
|
|
53 *err = FALSE;
|
|
54 if ( buf[ 0 ] == '.' )
|
|
55 {
|
|
56 if ( buf[ 1 ] == 0 )
|
|
57 return FALSE;
|
|
58 else
|
|
59 strcpy( line, buf + 1 );
|
|
60 }
|
|
61 else
|
|
62 strcpy( line, buf );
|
|
63 return TRUE;
|
|
64 }
|
|
65
|
|
66 Bool
|
|
67 Prt_putTxtLn( const char* line, FILE *f )
|
|
68 {
|
|
69 if ( line[ 0 ] == '.' )
|
|
70 {
|
|
71 Log_dbg( "[S] .%s", line );
|
|
72 return ( fprintf( f, ".%s\r\n", line ) == strlen( line ) + 3 );
|
|
73 }
|
|
74 else
|
|
75 {
|
|
76 Log_dbg( "[S] %s", line );
|
|
77 return ( fprintf( f, "%s\r\n", line ) == strlen( line ) + 2 );
|
|
78 }
|
|
79 }
|
|
80
|
|
81 Bool
|
|
82 Prt_putEndOfTxt( FILE *f )
|
|
83 {
|
|
84 Log_dbg( "[S] ." );
|
|
85 return ( fprintf( f, ".\r\n" ) == 3 );
|
|
86 }
|
|
87
|
|
88 /*
|
|
89 Write text buffer of lines each ending with '\n'.
|
|
90 Replace '\n' by "\r\n".
|
|
91 */
|
|
92 Bool
|
|
93 Prt_putTxtBuf( const char *buf, FILE *f )
|
|
94 {
|
|
95 Str line;
|
|
96 const char *pBuf;
|
|
97 char *pLn;
|
|
98
|
|
99 pBuf = buf;
|
|
100 pLn = line;
|
|
101 while ( *pBuf != '\0' )
|
|
102 {
|
|
103 if ( *pBuf == '\n' )
|
|
104 {
|
|
105 *pLn = '\0';
|
|
106 if ( ! Prt_putTxtLn( line, f ) )
|
|
107 return FALSE;
|
|
108 pLn = line;
|
|
109 ++pBuf;
|
|
110 }
|
|
111 else if ( pLn - line >= MAXCHAR - 1 )
|
|
112 {
|
|
113 /* Put it out raw to prevent String overflow */
|
|
114 Log_err( "Writing VERY long line" );
|
|
115 *pLn = '\0';
|
|
116 if ( fprintf( f, "%s", line ) != strlen( line ) )
|
|
117 return FALSE;
|
|
118 pLn = line;
|
|
119 }
|
|
120 else
|
|
121 *(pLn++) = *(pBuf++);
|
|
122 }
|
|
123 return TRUE;
|
|
124 }
|
|
125
|
|
126 Bool
|
|
127 Prt_getField( Str resultField, Str resultValue, const char* line )
|
|
128 {
|
|
129 char *dst;
|
|
130 const char *p;
|
|
131 Str lineLower, t;
|
|
132
|
|
133 Utl_cpyStr( lineLower, line );
|
|
134 Utl_toLower( lineLower );
|
|
135 p = Utl_stripWhiteSpace( lineLower );
|
|
136 dst = resultField;
|
|
137 while ( ! isspace( *p ) && *p != ':' && *p != '\0' )
|
|
138 *(dst++) = *(p++);
|
|
139 *dst = '\0';
|
|
140 while ( isspace( *p ) )
|
|
141 ++p;
|
|
142 if ( *p == ':' )
|
|
143 {
|
|
144 ++p;
|
|
145 strcpy( t, line + ( p - lineLower ) );
|
|
146 p = Utl_stripWhiteSpace( t );
|
|
147 strcpy( resultValue, p );
|
|
148 return TRUE;
|
|
149 }
|
|
150 return FALSE;
|
|
151 }
|
|
152
|
|
153 Bool
|
|
154 Prt_searchHeader( const char *artTxt, const char *which, Str result )
|
|
155 {
|
|
156 const char *src, *p;
|
|
157 char *dst;
|
|
158 Str line, whichLower, field;
|
|
159 int len;
|
|
160
|
|
161 Utl_cpyStr( whichLower, which );
|
|
162 Utl_toLower( whichLower );
|
|
163 src = artTxt;
|
|
164 while ( TRUE )
|
|
165 {
|
|
166 dst = line;
|
|
167 len = 0;
|
|
168 while ( *src != '\n' && len < MAXCHAR )
|
|
169 {
|
|
170 if ( *src == '\0' )
|
|
171 return FALSE;
|
|
172 *(dst++) = *(src++);
|
|
173 ++len;
|
|
174 }
|
|
175 if ( *src == '\n' )
|
|
176 ++src;
|
|
177 *dst = '\0';
|
|
178 p = Utl_stripWhiteSpace( line );
|
|
179 if ( *p == '\0' )
|
|
180 break;
|
|
181 if ( Prt_getField( field, result, line )
|
|
182 && strcmp( field, whichLower ) == 0 )
|
|
183 return TRUE;
|
|
184 }
|
|
185 return FALSE;
|
|
186 }
|
|
187
|
|
188 static Bool
|
|
189 getFQDN( Str result )
|
|
190 {
|
|
191 struct hostent *myHostEnt;
|
|
192 struct utsname myName;
|
|
193
|
|
194 if ( uname( &myName ) >= 0
|
|
195 && ( myHostEnt = gethostbyname( myName.nodename ) ) )
|
|
196 {
|
|
197 Utl_cpyStr( result, myHostEnt->h_name );
|
|
198 return TRUE;
|
|
199 }
|
|
200 return FALSE;
|
|
201 }
|
|
202
|
|
203 static void
|
|
204 getDomain( Str domain, const char *from )
|
|
205 {
|
|
206 const char *addTopLevel, *p1, *p2, *p, *domainStart;
|
|
207 Str myDomain;
|
|
208
|
|
209 if ( getFQDN( myDomain ) )
|
|
210 {
|
|
211 p = strstr( myDomain, "." );
|
|
212 if ( p != NULL )
|
|
213 domainStart = p + 1;
|
|
214 else
|
|
215 domainStart = myDomain;
|
|
216 }
|
|
217 else /* Take domain of From field */
|
|
218 {
|
|
219 myDomain[ 0 ] = '\0';
|
|
220 p1 = strstr( from, "@" );
|
|
221 if ( p1 != NULL )
|
|
222 {
|
|
223 p2 = strstr( p1, ">" );
|
|
224 if ( p2 != NULL )
|
|
225 Utl_cpyStrN( myDomain, p1 + 1, p2 - p1 - 1 );
|
|
226 }
|
|
227 if ( myDomain[ 0 ] == '\0' )
|
|
228 Utl_cpyStr( myDomain, "unknown" );
|
|
229 domainStart = myDomain;
|
|
230 }
|
|
231 /*
|
|
232 If domain contains no dot (and is probably invalid anyway),
|
|
233 we add ".local", because some servers insist on domainnames with dot
|
|
234 in message ID.
|
|
235 */
|
|
236 addTopLevel = strstr( domainStart, "." ) == NULL ? ".local" : "";
|
|
237 snprintf( domain, MAXCHAR, "%s%s", myDomain, addTopLevel );
|
|
238 }
|
|
239
|
10
|
240 /* See RFC 850, section 2.1.7 */
|
0
|
241 Bool
|
|
242 Prt_isValidMsgId( const char *msgId )
|
|
243 {
|
|
244 Str head, domain;
|
|
245 int len, headLen;
|
|
246 const char *p;
|
|
247
|
|
248 len = strlen( msgId );
|
|
249 p = strstr( msgId, "@" );
|
|
250 if ( msgId[ 0 ] != '<' || msgId[ len - 1 ] != '>' || p == NULL )
|
|
251 return FALSE;
|
|
252 strcpy( domain, p + 1 );
|
|
253 domain[ strlen( domain ) - 1 ] = '\0';
|
|
254 headLen = p - msgId - 1;
|
|
255 Utl_cpyStrN( head, msgId + 1, headLen );
|
|
256 head[ headLen ] = '\0';
|
|
257 /*
|
|
258 To do: check for special characters in head and domain (non-printable
|
|
259 or '@', '<', '>'). Maybe compare domain with a config option
|
|
260 and replace it by the config option, if not equal.
|
|
261 */
|
|
262 if ( strstr( domain, "." ) == NULL )
|
|
263 return FALSE;
|
|
264 return TRUE;
|
|
265 }
|
|
266
|
|
267 void
|
|
268 Prt_genMsgId( Str msgId, const char *from, const char *suffix )
|
|
269 {
|
|
270 Str domain, date;
|
|
271 time_t t;
|
|
272
|
|
273 getDomain( domain, from );
|
|
274 time( &t );
|
|
275 strftime( date, MAXCHAR, "%Y%m%d%H%M%S", gmtime( &t ) );
|
|
276 srand( time( NULL ) );
|
|
277 snprintf( msgId, MAXCHAR, "<%s.%X.%s@%s>", date, rand(), suffix, domain );
|
|
278 ASSERT( Prt_isValidMsgId( msgId ) );
|
|
279 }
|