Fix some of the Errors/warnings detected by checkapi.
[metze/wireshark/wip.git] / epan / dissectors / packet-smtp.c
1 /* packet-smtp.c
2  * Routines for SMTP packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2000 by Richard Sharpe <rsharpe@ns.aus.com>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <glib.h>
36 #include <string.h>
37 #include <epan/packet.h>
38 #include <epan/conversation.h>
39 #include <epan/addr_resolv.h>
40 #include <epan/prefs.h>
41 #include <epan/strutil.h>
42 #include <epan/emem.h>
43 #include <epan/reassemble.h>
44
45 /* RFC 2821 */
46 #define TCP_PORT_SMTP 25
47
48 /* RFC 4409 */
49 #define TCP_PORT_SUBMISSION 587
50
51 static int proto_smtp = -1;
52
53 static int hf_smtp_req = -1;
54 static int hf_smtp_rsp = -1;
55 static int hf_smtp_req_command = -1;
56 static int hf_smtp_req_parameter = -1;
57 static int hf_smtp_rsp_code = -1;
58 static int hf_smtp_rsp_parameter = -1;
59
60 static int hf_smtp_data_fragments = -1;
61 static int hf_smtp_data_fragment = -1;
62 static int hf_smtp_data_fragment_overlap = -1;
63 static int hf_smtp_data_fragment_overlap_conflicts = -1;
64 static int hf_smtp_data_fragment_multiple_tails = -1;
65 static int hf_smtp_data_fragment_too_long_fragment = -1;
66 static int hf_smtp_data_fragment_error = -1;
67 static int hf_smtp_data_reassembled_in = -1;
68
69 static int ett_smtp = -1;
70 static int ett_smtp_cmdresp = -1;
71
72 static gint ett_smtp_data_fragment = -1;
73 static gint ett_smtp_data_fragments = -1;
74
75 /* desegmentation of SMTP command and response lines */
76 static gboolean smtp_desegment = TRUE;
77 static gboolean smtp_data_desegment = TRUE;
78
79 static GHashTable *smtp_data_segment_table = NULL;
80 static GHashTable *smtp_data_reassembled_table = NULL;
81
82 static const fragment_items smtp_data_frag_items = {
83         /* Fragment subtrees */
84         &ett_smtp_data_fragment,
85         &ett_smtp_data_fragments,
86         /* Fragment fields */
87         &hf_smtp_data_fragments,
88         &hf_smtp_data_fragment,
89         &hf_smtp_data_fragment_overlap,
90         &hf_smtp_data_fragment_overlap_conflicts,
91         &hf_smtp_data_fragment_multiple_tails,
92         &hf_smtp_data_fragment_too_long_fragment,
93         &hf_smtp_data_fragment_error,
94         /* Reassembled in field */
95         &hf_smtp_data_reassembled_in,
96         /* Tag */
97         "DATA fragments"
98 };
99
100 static  dissector_handle_t imf_handle = NULL;
101
102 /*
103  * A CMD is an SMTP command, MESSAGE is the message portion, and EOM is the
104  * last part of a message
105  */
106
107 #define SMTP_PDU_CMD     0
108 #define SMTP_PDU_MESSAGE 1
109 #define SMTP_PDU_EOM     2
110
111 struct smtp_proto_data {
112   guint16 pdu_type;
113   guint16 conversation_id;
114   gboolean more_frags;
115 };
116
117 /*
118  * State information stored with a conversation.
119  */
120 struct smtp_request_val {
121   gboolean reading_data; /* Reading message data, not commands */
122   gboolean crlf_seen;    /* Have we seen a CRLF on the end of a packet */
123   gboolean data_seen;    /* Have we seen a DATA command yet */
124   guint32 msg_read_len;  /* Length of BDAT message read so far */
125   guint32 msg_tot_len;   /* Total length of BDAT message */
126   gboolean msg_last;     /* Is this the last BDAT chunk */
127 };
128
129
130 static void dissect_smtp_data(tvbuff_t *tvb, int offset, proto_tree *smtp_tree)
131 {
132   gint next_offset;
133
134   while (tvb_offset_exists(tvb, offset)) {
135
136     /*
137      * Find the end of the line.
138      */
139     tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
140
141     /*
142      * Put this line.
143      */
144     proto_tree_add_text(smtp_tree, tvb, offset, next_offset - offset,
145                         "Message: %s",
146                         tvb_format_text(tvb, offset, next_offset - offset));
147
148     /*
149      * Step to the next line.
150      */
151     offset = next_offset;
152               
153   }
154
155 }
156
157 static void
158 dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
159 {
160     struct smtp_proto_data  *frame_data;
161     proto_tree              *smtp_tree;
162     proto_tree              *cmdresp_tree;
163     proto_item              *ti, *hidden_item;
164     int                     offset = 0;
165     int                     request = 0;
166     conversation_t          *conversation;
167     struct smtp_request_val *request_val;
168     const guchar            *line;
169     guint32                 code;
170     int                     linelen = 0;
171     gint                    length_remaining;
172     gboolean                eom_seen = FALSE;
173     gint                    next_offset;
174     gint                    loffset;
175     gboolean                is_continuation_line;
176     int                     cmdlen;
177     fragment_data           *frag_msg = NULL;
178     tvbuff_t                *next_tvb;
179
180     /* As there is no guarantee that we will only see frames in the
181      * the SMTP conversation once, and that we will see them in
182      * order - in Wireshark, the user could randomly click on frames
183      * in the conversation in any order in which they choose - we
184      * have to store information with each frame indicating whether
185      * it contains commands or data or an EOM indication.
186      *
187      * XXX - what about frames that contain *both*?  TCP is a
188      * byte-stream protocol, and there are no guarantees that
189      * TCP segment boundaries will correspond to SMTP commands
190      * or EOM indications.
191      *
192      * We only need that for the client->server stream; responses
193      * are easy to manage.
194      *
195      * If we have per frame data, use that, else, we must be on the first
196      * pass, so we figure it out on the first pass.
197      */
198
199     /* Find out what conversation this packet is part of ... but only
200      * if we have no information on this packet, so find the per-frame
201      * info first.
202      */
203
204     /* SMTP messages have a simple format ... */
205
206     request = pinfo -> destport == pinfo -> match_port;
207
208     /*
209      * Get the first line from the buffer.
210      *
211      * Note that "tvb_find_line_end()" will, if it doesn't return
212      * -1, return a value that is not longer than what's in the buffer,
213      * and "tvb_find_line_end()" will always return a value that is not
214      * longer than what's in the buffer, so the "tvb_get_ptr()" call
215      * won't throw an exception.
216      */
217
218     frame_data = p_get_proto_data(pinfo->fd, proto_smtp);
219
220     if (!frame_data) {
221
222       conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
223                                        pinfo->srcport, pinfo->destport, 0);
224       if (conversation == NULL) { /* No conversation, create one */
225         conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
226                                         pinfo->srcport, pinfo->destport, 0);
227
228       }
229
230       /*
231        * Is there a request structure attached to this conversation?
232        */
233       request_val = conversation_get_proto_data(conversation, proto_smtp);
234
235       if (!request_val) {
236
237         /*
238          * No - create one and attach it.
239          */
240         request_val = se_alloc(sizeof(struct smtp_request_val));
241         request_val->reading_data = FALSE;
242         request_val->crlf_seen = FALSE;
243         request_val->data_seen = FALSE;
244         request_val->msg_read_len = 0;
245         request_val->msg_tot_len = 0;
246         request_val->msg_last = TRUE;
247
248         conversation_add_proto_data(conversation, proto_smtp, request_val);
249
250       }
251
252       if(request) {
253         frame_data = se_alloc(sizeof(struct smtp_proto_data));
254
255         frame_data->conversation_id = conversation->index;
256         frame_data->more_frags = TRUE;
257
258         p_add_proto_data(pinfo->fd, proto_smtp, frame_data);    
259
260       }
261
262     loffset = offset;
263     while (tvb_offset_exists(tvb, loffset)) {
264
265     linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset,
266       smtp_desegment && pinfo->can_desegment);
267     if (linelen == -1) {
268
269       if(offset == loffset) {
270       /*
271        * We didn't find a line ending, and we're doing desegmentation;
272        * tell the TCP dissector where the data for this message starts
273        * in the data it handed us, and tell it we need one more byte
274        * (we may need more, but we'll try again if what we get next
275        * isn't enough), and return.
276        */
277       pinfo->desegment_offset = loffset;
278       pinfo->desegment_len = 1;
279       return;
280       }
281       else {
282         linelen = tvb_length_remaining(tvb, loffset);
283         next_offset = loffset + linelen;
284       }
285     }
286     line = tvb_get_ptr(tvb, loffset, linelen);
287
288       /*
289        * Check whether or not this packet is an end of message packet
290        * We should look for CRLF.CRLF and they may be split.
291        * We have to keep in mind that we may see what we want on
292        * two passes through here ...
293        */
294
295       if (request_val->reading_data) {
296
297         /*
298          * The order of these is important ... We want to avoid
299          * cases where there is a CRLF at the end of a packet and a
300          * .CRLF at the begining of the same packet.
301          */
302
303         if ((request_val->crlf_seen && tvb_strneql(tvb, loffset, ".\r\n", 3) == 0) ||
304             tvb_strneql(tvb, loffset, "\r\n.\r\n", 5) == 0) {
305
306           eom_seen = TRUE;
307
308         } 
309
310         length_remaining = tvb_length_remaining(tvb, loffset);
311         if (length_remaining == tvb_reported_length_remaining(tvb, loffset) &&
312             tvb_strneql(tvb, loffset + length_remaining - 2, "\r\n", 2) == 0) {
313
314           request_val->crlf_seen = TRUE;
315
316         }
317         else {
318
319           request_val->crlf_seen = FALSE;
320
321         }
322       }
323
324     /*
325      * OK, Check if we have seen a DATA request. We do it here for
326      * simplicity, but we have to be careful below.
327      */
328
329       if (request) {
330
331         if (request_val->reading_data) {
332           /*
333            * This is message data.
334            */
335           if (eom_seen) { /* Seen the EOM */
336             /*
337              * EOM.
338              * Everything that comes after it is commands.
339              *
340              * XXX - what if the EOM isn't at the beginning of
341              * the TCP segment?  It can occur anywhere....
342              */
343             frame_data->pdu_type = SMTP_PDU_EOM;
344             request_val->reading_data = FALSE;
345             
346             break;
347             
348           } else {
349             /*
350              * Message data with no EOM.
351              */
352             frame_data->pdu_type = SMTP_PDU_MESSAGE;
353
354             if (request_val->msg_tot_len > 0) {
355               /* 
356                * We are handling a BDAT message.
357                * Check if we have reached end of the data chunk.
358                */
359               request_val->msg_read_len += tvb_length_remaining(tvb, loffset);
360
361               if (request_val->msg_read_len == request_val->msg_tot_len) {
362                 /* 
363                  * We have reached end of BDAT data chunk.
364                  * Everything that comes after this is commands.
365                  */
366                 request_val->reading_data = FALSE;
367
368                 if (request_val->msg_last) {
369                   /* 
370                    * We have found the LAST data chunk.
371                    * The message can now be reassembled.
372                    */
373                   frame_data->more_frags = FALSE;
374                 }
375                 
376                 break; /* no need to go through the remaining lines */
377               }
378             }
379           }
380         } else {
381           /*
382            * This is commands - unless the capture started in the
383            * middle of a session, and we're in the middle of data.
384            * To quote RFC 821, "Command codes are four alphabetic
385            * characters"; if we don't see four alphabetic characters
386            * and, if there's anything else in the line, a space, we
387            * assume it's not a command.
388            * (We treat only A-Z and a-z as alphabetic.)
389            */
390 #define ISALPHA(c)      (((c) >= 'A' && (c) <= 'Z') || \
391                          ((c) >= 'a' && (c) <= 'z'))
392           if (linelen >= 4 && ISALPHA(line[0]) && ISALPHA(line[1]) &&
393               ISALPHA(line[2]) && ISALPHA(line[3]) &&
394               (linelen == 4 || line[4] == ' ')) {
395             if (g_ascii_strncasecmp(line, "DATA", 4) == 0) {
396
397               /*
398                * DATA command.
399                * This is a command, but everything that comes after it,
400                * until an EOM, is data.
401                */
402               frame_data->pdu_type = SMTP_PDU_CMD;
403               request_val->reading_data = TRUE;
404               request_val->data_seen = TRUE;
405
406             } else if (g_ascii_strncasecmp(line, "BDAT", 4) == 0) {
407
408               /*
409                * BDAT command.
410                * This is a command, but everything that comes after it,
411                * until given length is received, is data.
412                */
413               guint32 msg_len;
414
415               msg_len = strtoul (line+5, NULL, 10);
416
417               frame_data->pdu_type = SMTP_PDU_CMD;
418               request_val->data_seen = TRUE;
419               request_val->msg_tot_len += msg_len;
420
421               if (msg_len == 0) {
422                 /* No data to read, next will be a command */
423                 request_val->reading_data = FALSE;
424               } else {
425                 request_val->reading_data = TRUE;
426               }
427
428               if (g_ascii_strncasecmp(line+linelen-4, "LAST", 4) == 0) {
429                 /*
430                  * This is the last data chunk.
431                  */
432                 request_val->msg_last = TRUE;
433
434                 if (msg_len == 0) {
435                   /* 
436                    * No more data to expect.
437                    * The message can now be reassembled.
438                    */
439                   frame_data->more_frags = FALSE;
440                 }
441               } else {
442                 request_val->msg_last = FALSE;
443               }
444
445             } else {
446
447               /*
448                * Regular command.
449                */
450               frame_data->pdu_type = SMTP_PDU_CMD;
451
452             }
453           } else {
454                 if ((linelen >= 7) && line[0] == 'X' && ( (g_ascii_strncasecmp(line, "X-EXPS ", 7) == 0) ||
455                         ((linelen >=13) && (g_ascii_strncasecmp(line, "X-LINK2STATE ", 13) == 0)) || 
456                         ((linelen >= 8) && (g_ascii_strncasecmp(line, "XEXCH50 ", 8) == 0)) ))
457                                 frame_data->pdu_type = SMTP_PDU_CMD;
458                 else
459             /*
460              * Assume it's message data.
461              */
462
463                   
464             frame_data->pdu_type = request_val->data_seen ? SMTP_PDU_MESSAGE : SMTP_PDU_CMD;
465
466           }
467         }
468       }
469
470       /*
471        * Step past this line.
472        */
473       loffset = next_offset;
474
475     }
476     }
477
478     /*
479      * From here, we simply add items to the tree and info to the info
480      * fields ...
481      */
482
483     if (check_col(pinfo->cinfo, COL_PROTOCOL))
484       col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMTP");
485
486     if (check_col(pinfo->cinfo, COL_INFO)) {  /* Add the appropriate type here */
487       col_clear(pinfo->cinfo, COL_INFO);
488
489       /*
490        * If it is a request, we have to look things up, otherwise, just
491        * display the right things
492        */
493
494       if (request) {
495
496         /* We must have frame_data here ... */
497
498         switch (frame_data->pdu_type) {
499         case SMTP_PDU_MESSAGE:
500
501           length_remaining = tvb_length_remaining(tvb, offset);
502           col_set_str(pinfo->cinfo, COL_INFO, smtp_data_desegment ? "C: DATA fragment" : "C: Message Body");
503           col_append_fstr(pinfo->cinfo, COL_INFO, ", %d byte%s", length_remaining,
504                           plurality (length_remaining, "", "s"));
505           break;
506
507         case SMTP_PDU_EOM:
508
509           col_set_str(pinfo->cinfo, COL_INFO, "C: .");
510
511           break;
512
513         case SMTP_PDU_CMD:
514
515           loffset = offset;
516           while (tvb_offset_exists(tvb, loffset)) {
517             /*
518              * Find the end of the line.
519              */
520             linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE);
521             line = tvb_get_ptr(tvb, loffset, linelen);
522
523             if(loffset == offset) 
524               col_append_fstr(pinfo->cinfo, COL_INFO, "C: %s",
525                            format_text(line, linelen));
526             else {
527               col_append_fstr(pinfo->cinfo, COL_INFO, " | %s",
528                            format_text(line, linelen));
529             }
530
531             loffset = next_offset;
532
533           }
534           break;
535
536         }
537
538       }
539       else {
540
541           loffset = offset;
542           while (tvb_offset_exists(tvb, loffset)) {
543             /*
544              * Find the end of the line.
545              */
546             linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE);
547             line = tvb_get_ptr(tvb, loffset, linelen);
548
549             if(loffset == offset) 
550               col_append_fstr(pinfo->cinfo, COL_INFO, "S: %s",
551                            format_text(line, linelen));
552             else {
553               col_append_fstr(pinfo->cinfo, COL_INFO, " | %s",
554                            format_text(line, linelen));
555             }
556
557             loffset = next_offset;
558           }
559       }
560     }
561
562     if (tree) { /* Build the tree info ... */
563
564       ti = proto_tree_add_item(tree, proto_smtp, tvb, offset, -1, FALSE);
565       smtp_tree = proto_item_add_subtree(ti, ett_smtp);
566       if (request) {
567
568         /*
569          * Check out whether or not we can see a command in there ...
570          * What we are looking for is not data_seen and the word DATA
571          * and not eom_seen.
572          *
573          * We will see DATA and request_val->data_seen when we process the
574          * tree view after we have seen a DATA packet when processing
575          * the packet list pane.
576          *
577          * On the first pass, we will not have any info on the packets
578          * On second and subsequent passes, we will.
579          */
580
581         switch (frame_data->pdu_type) {
582
583         case SMTP_PDU_MESSAGE:
584
585           if(smtp_data_desegment) {
586
587             frag_msg = fragment_add_seq_next (tvb, 0, pinfo, frame_data->conversation_id, 
588                                               smtp_data_segment_table, smtp_data_reassembled_table, 
589                                               tvb_length(tvb), frame_data->more_frags);
590           } else {
591             
592             /*
593              * Message body.
594              * Put its lines into the protocol tree, a line at a time.
595              */
596
597             dissect_smtp_data(tvb, offset, smtp_tree);
598             
599           }
600
601           break;
602
603         case SMTP_PDU_EOM:
604
605           /*
606            * End-of-message-body indicator.
607            *
608            * XXX - what about stuff after the first line?
609            * Unlikely, as the client should wait for a response to the
610            * DATA command this terminates before sending another
611            * request, but we should probably handle it.
612            */
613           proto_tree_add_text(smtp_tree, tvb, offset, linelen, "C: .");
614
615           if(smtp_data_desegment) {
616
617             /* terminate the desegmentation */
618             frag_msg = fragment_end_seq_next (pinfo, frame_data->conversation_id, smtp_data_segment_table,
619                                               smtp_data_reassembled_table);
620           }
621
622           break;
623
624         case SMTP_PDU_CMD:
625
626           /*
627            * Command.
628            *
629            * XXX - what about stuff after the first line?
630            * Unlikely, as the client should wait for a response to the
631            * previous command before sending another request, but we
632            * should probably handle it.
633            */
634
635           loffset = offset;
636         while (tvb_offset_exists(tvb, loffset)) {
637
638           /*
639            * Find the end of the line.
640            */
641           linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE);
642
643           if (linelen >= 4)
644             cmdlen = 4;
645           else
646             cmdlen = linelen;
647           hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_req, tvb,
648                                         0, 0, TRUE);
649           PROTO_ITEM_SET_HIDDEN(hidden_item);
650           /*
651            * Put the command line into the protocol tree.
652            */
653           ti = proto_tree_add_text(smtp_tree, tvb, loffset, next_offset - loffset,
654                 "Command: %s",
655                 tvb_format_text(tvb, loffset, next_offset - loffset));
656           cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp);
657
658           proto_tree_add_item(cmdresp_tree, hf_smtp_req_command, tvb,
659                               loffset, cmdlen, FALSE);
660           if (linelen > 5) {
661             proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb,
662                                 loffset + 5, linelen - 5, FALSE);
663           }
664
665           if (smtp_data_desegment && !frame_data->more_frags) {
666
667             /* terminate the desegmentation */
668             frag_msg = fragment_end_seq_next (pinfo, frame_data->conversation_id, smtp_data_segment_table,
669                                               smtp_data_reassembled_table);
670           }
671
672           /*
673            * Step past this line.
674            */
675           loffset = next_offset;
676           
677         }
678         }
679
680         if (smtp_data_desegment) {
681           next_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled DATA",
682                                                frag_msg, &smtp_data_frag_items, NULL, smtp_tree);
683           if (next_tvb) {
684             /* XXX: this is presumptious - we may have negotiated something else */
685             if(imf_handle) {
686               call_dissector(imf_handle, next_tvb, pinfo, tree);
687             } else {
688               
689               /*
690                * Message body.
691                * Put its lines into the protocol tree, a line at a time.
692                */
693               
694               dissect_smtp_data(tvb, offset, smtp_tree);
695               
696             }
697             
698             pinfo->fragmented = FALSE;
699           } else {
700             pinfo->fragmented = TRUE;
701           }
702         }
703       }
704       else {
705
706         /*
707          * Process the response, a line at a time, until we hit a line
708          * that doesn't have a continuation indication on it.
709          */
710         hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_rsp, tvb,
711                                         0, 0, TRUE);
712         PROTO_ITEM_SET_HIDDEN(hidden_item);
713
714         while (tvb_offset_exists(tvb, offset)) {
715
716           /*
717            * Find the end of the line.
718            */
719           linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
720
721           /*
722            * Put it into the protocol tree.
723            */
724           ti = proto_tree_add_text(smtp_tree, tvb, offset,
725                                    next_offset - offset, "Response: %s",
726                                    tvb_format_text(tvb, offset,
727                                                    next_offset - offset));
728           cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp);
729
730           /*
731            * Is it a continuation line?
732            */
733           is_continuation_line =
734               (linelen >= 4 && tvb_get_guint8(tvb, offset + 3) == '-');
735
736           /*
737            * Put the response code and parameters into the protocol tree.
738            */
739           line = tvb_get_ptr(tvb, offset, linelen);
740           if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1])
741                            && isdigit(line[2])) {
742             /*
743              * We have a 3-digit response code.
744              */
745             code = (line[0] - '0')*100 + (line[1] - '0')*10 + (line[2] - '0');
746             proto_tree_add_uint(cmdresp_tree, hf_smtp_rsp_code, tvb, offset, 3,
747                                 code);
748
749             if (linelen >= 4) {
750               proto_tree_add_item(cmdresp_tree, hf_smtp_rsp_parameter, tvb,
751                                   offset + 4, linelen - 4, FALSE);
752             }
753           }
754
755           /*
756            * Step past this line.
757            */
758           offset = next_offset;
759
760           /*
761            * If it's not a continuation line, quit.
762            */
763           /* if (!is_continuation_line)
764              break; */
765
766         }
767
768       }
769     }
770 }
771
772 static void smtp_data_reassemble_init (void)
773 {
774         fragment_table_init (&smtp_data_segment_table);
775         reassembled_table_init (&smtp_data_reassembled_table);
776 }
777
778
779 /* Register all the bits needed by the filtering engine */
780
781 void
782 proto_register_smtp(void)
783 {
784   static hf_register_info hf[] = {
785     { &hf_smtp_req,
786       { "Request", "smtp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
787
788     { &hf_smtp_rsp,
789       { "Response", "smtp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
790
791     { &hf_smtp_req_command,
792       { "Command", "smtp.req.command", FT_STRING,  BASE_NONE, NULL, 0x0,
793         "", HFILL }},
794
795     { &hf_smtp_req_parameter,
796       { "Request parameter", "smtp.req.parameter", FT_STRING, BASE_NONE, NULL, 0x0,
797         "", HFILL }},
798
799     { &hf_smtp_rsp_code,
800       { "Response code", "smtp.response.code", FT_UINT32, BASE_DEC, NULL, 0x0,
801         "", HFILL }},
802
803     { &hf_smtp_rsp_parameter,
804       { "Response parameter", "smtp.rsp.parameter", FT_STRING, BASE_NONE, NULL, 0x0,
805         "", HFILL }},
806
807     /* Fragment entries */
808     { &hf_smtp_data_fragments,
809       { "DATA fragments", "smtp.data.fragments", FT_NONE, BASE_NONE,
810         NULL, 0x00, "Message fragments", HFILL } },
811     { &hf_smtp_data_fragment,
812       { "DATA fragment", "smtp.data.fragment", FT_FRAMENUM, BASE_NONE,
813         NULL, 0x00, "Message fragment", HFILL } },
814     { &hf_smtp_data_fragment_overlap,
815       { "DATA fragment overlap", "smtp.data.fragment.overlap", FT_BOOLEAN,
816         BASE_NONE, NULL, 0x00, "Message fragment overlap", HFILL } },
817     { &hf_smtp_data_fragment_overlap_conflicts,
818       { "DATA fragment overlapping with conflicting data",
819         "smtp.data.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL,
820         0x00, "Message fragment overlapping with conflicting data", HFILL } },
821     { &hf_smtp_data_fragment_multiple_tails,
822       { "DATA has multiple tail fragments",
823         "smtp.data.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE,
824         NULL, 0x00, "Message has multiple tail fragments", HFILL } },
825     { &hf_smtp_data_fragment_too_long_fragment,
826       { "DATA fragment too long", "smtp.data.fragment.too_long_fragment",
827         FT_BOOLEAN, BASE_NONE, NULL, 0x00, "Message fragment too long",
828         HFILL } },
829     { &hf_smtp_data_fragment_error,
830       { "DATA defragmentation error", "smtp.data.fragment.error", FT_FRAMENUM,
831         BASE_NONE, NULL, 0x00, "Message defragmentation error", HFILL } },
832     { &hf_smtp_data_reassembled_in,
833       { "Reassembled DATA in frame", "smtp.data.reassembled.in", FT_FRAMENUM, BASE_NONE,
834         NULL, 0x00, "This DATA fragment is reassembled in this frame", HFILL } },
835   };
836   static gint *ett[] = {
837     &ett_smtp,
838     &ett_smtp_cmdresp,
839     &ett_smtp_data_fragment,
840     &ett_smtp_data_fragments,
841
842   };
843   module_t *smtp_module;
844
845   proto_smtp = proto_register_protocol("Simple Mail Transfer Protocol",
846                                        "SMTP", "smtp");
847
848   proto_register_field_array(proto_smtp, hf, array_length(hf));
849   proto_register_subtree_array(ett, array_length(ett));
850   register_init_routine (&smtp_data_reassemble_init);
851
852   /* Allow dissector to find be found by name. */
853   register_dissector("smtp", dissect_smtp, proto_smtp);
854
855   /* Preferences */
856   smtp_module = prefs_register_protocol(proto_smtp, NULL);
857   prefs_register_bool_preference(smtp_module, "desegment_lines",
858     "Reassemble SMTP command and response lines\nspanning multiple TCP segments",
859     "Whether the SMTP dissector should reassemble command and response lines spanning multiple TCP segments."
860     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
861     &smtp_desegment);
862
863   prefs_register_bool_preference(smtp_module, "desegment_data",
864     "Reassemble SMTP DATA commands spanning multiple TCP segments",
865     "Whether the SMTP dissector should reassemble DATA command and lines spanning multiple TCP segments."
866     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
867     &smtp_data_desegment);
868
869 }
870
871 /* The registration hand-off routine */
872 void
873 proto_reg_handoff_smtp(void)
874 {
875   dissector_handle_t smtp_handle;
876
877   smtp_handle = create_dissector_handle(dissect_smtp, proto_smtp);
878   dissector_add("tcp.port", TCP_PORT_SMTP, smtp_handle);
879   dissector_add("tcp.port", TCP_PORT_SUBMISSION, smtp_handle);
880
881   /* find the IMF dissector */
882   imf_handle = find_dissector("imf");
883
884 }