1 /* 2 * libEtPan! -- a mail stuff library 3 * 4 * Copyright (C) 2001 - 2003 - DINH Viet Hoa 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the libEtPan! project nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 33 /* 34 * $Id$ 35 */ 36 37 #ifndef MAILIMF_TYPES_H 38 39 #define MAILIMF_TYPES_H 40 41 #ifdef __cplusplus 42 extern "C" { 43 #endif 44 45 #include "clist.h" 46 #include <sys/types.h> 47 48 /* 49 IMPORTANT NOTE: 50 51 All allocation functions will take as argument allocated data 52 and will store these data in the structure they will allocate. 53 Data should be persistant during all the use of the structure 54 and will be freed by the free function of the structure 55 56 allocation functions will return NULL on failure 57 */ 58 59 /* 60 mailimf_date_time is a date 61 62 - day is the day of month (1 to 31) 63 64 - month (1 to 12) 65 66 - year (4 digits) 67 68 - hour (0 to 23) 69 70 - min (0 to 59) 71 72 - sec (0 to 59) 73 74 - zone (this is the decimal value that we can read, for example: 75 for "-0200", the value is -200) 76 */ 77 78 struct mailimf_date_time { 79 int dt_day; 80 int dt_month; 81 int dt_year; 82 int dt_hour; 83 int dt_min; 84 int dt_sec; 85 int dt_zone; 86 }; 87 88 struct mailimf_date_time * 89 mailimf_date_time_new(int dt_day, int dt_month, int dt_year, 90 int dt_hour, int dt_min, int dt_sec, int dt_zone); 91 92 void mailimf_date_time_free(struct mailimf_date_time * date_time); 93 94 95 96 /* this is the type of address */ 97 98 enum { 99 MAILIMF_ADDRESS_ERROR, /* on parse error */ 100 MAILIMF_ADDRESS_MAILBOX, /* if this is a mailbox (mailbox@domain) */ 101 MAILIMF_ADDRESS_GROUP, /* if this is a group 102 (group_name: address1@domain1, 103 address2@domain2; ) */ 104 }; 105 106 /* 107 mailimf_address is an address 108 109 - type can be MAILIMF_ADDRESS_MAILBOX or MAILIMF_ADDRESS_GROUP 110 111 - mailbox is a mailbox if type is MAILIMF_ADDRESS_MAILBOX 112 113 - group is a group if type is MAILIMF_ADDRESS_GROUP 114 */ 115 116 struct mailimf_address { 117 int ad_type; 118 union { 119 struct mailimf_mailbox * ad_mailbox; /* can be NULL */ 120 struct mailimf_group * ad_group; /* can be NULL */ 121 } ad_data; 122 }; 123 124 125 struct mailimf_address * 126 mailimf_address_new(int ad_type, struct mailimf_mailbox * ad_mailbox, 127 struct mailimf_group * ad_group); 128 129 void mailimf_address_free(struct mailimf_address * address); 130 131 132 133 /* 134 mailimf_mailbox is a mailbox 135 136 - display_name is the name that will be displayed for this mailbox, 137 for example 'name' in '"name" <mailbox@domain>, 138 should be allocated with malloc() 139 140 - addr_spec is the mailbox, for example 'mailbox@domain' 141 in '"name" <mailbox@domain>, should be allocated with malloc() 142 */ 143 144 struct mailimf_mailbox { 145 char * mb_display_name; /* can be NULL */ 146 char * mb_addr_spec; /* != NULL */ 147 }; 148 149 struct mailimf_mailbox * 150 mailimf_mailbox_new(char * mb_display_name, char * mb_addr_spec); 151 152 void mailimf_mailbox_free(struct mailimf_mailbox * mailbox); 153 154 155 156 /* 157 mailimf_group is a group 158 159 - display_name is the name that will be displayed for this group, 160 for example 'group_name' in 161 'group_name: address1@domain1, address2@domain2;', should be allocated 162 with malloc() 163 164 - mb_list is a list of mailboxes 165 */ 166 167 struct mailimf_group { 168 char * grp_display_name; /* != NULL */ 169 struct mailimf_mailbox_list * grp_mb_list; /* can be NULL */ 170 }; 171 172 struct mailimf_group * 173 mailimf_group_new(char * grp_display_name, 174 struct mailimf_mailbox_list * grp_mb_list); 175 176 void mailimf_group_free(struct mailimf_group * group); 177 178 179 180 /* 181 mailimf_mailbox_list is a list of mailboxes 182 183 - list is a list of mailboxes 184 */ 185 186 struct mailimf_mailbox_list { 187 clist * mb_list; /* list of (struct mailimf_mailbox *) */ 188 /* != NULL */ 189 }; 190 191 struct mailimf_mailbox_list * 192 mailimf_mailbox_list_new(clist * mb_list); 193 194 void mailimf_mailbox_list_free(struct mailimf_mailbox_list * mb_list); 195 196 197 198 /* 199 mailimf_address_list is a list of addresses 200 201 - list is a list of addresses 202 */ 203 204 struct mailimf_address_list { 205 clist * ad_list; /* list of (struct mailimf_address *) */ 206 /* != NULL */ 207 }; 208 209 struct mailimf_address_list * 210 mailimf_address_list_new(clist * ad_list); 211 212 void mailimf_address_list_free(struct mailimf_address_list * addr_list); 213 214 215 216 217 218 /* 219 mailimf_body is the text part of a message 220 221 - text is the beginning of the text part, it is a substring 222 of an other string 223 224 - size is the size of the text part 225 */ 226 227 struct mailimf_body { 228 const char * bd_text; /* != NULL */ 229 size_t bd_size; 230 }; 231 232 struct mailimf_body * mailimf_body_new(const char * bd_text, size_t bd_size); 233 234 void mailimf_body_free(struct mailimf_body * body); 235 236 237 238 239 /* 240 mailimf_message is the content of the message 241 242 - fields is the header fields of the message 243 244 - body is the text part of the message 245 */ 246 247 struct mailimf_message { 248 struct mailimf_fields * msg_fields; /* != NULL */ 249 struct mailimf_body * msg_body; /* != NULL */ 250 }; 251 252 struct mailimf_message * 253 mailimf_message_new(struct mailimf_fields * msg_fields, 254 struct mailimf_body * msg_body); 255 256 void mailimf_message_free(struct mailimf_message * message); 257 258 259 260 261 /* 262 mailimf_fields is a list of header fields 263 264 - list is a list of header fields 265 */ 266 267 struct mailimf_fields { 268 clist * fld_list; /* list of (struct mailimf_field *) */ 269 /* != NULL */ 270 }; 271 272 struct mailimf_fields * mailimf_fields_new(clist * fld_list); 273 274 void mailimf_fields_free(struct mailimf_fields * fields); 275 276 277 278 /* this is a type of field */ 279 280 enum { 281 MAILIMF_FIELD_NONE, /* on parse error */ 282 MAILIMF_FIELD_RETURN_PATH, /* Return-Path */ 283 MAILIMF_FIELD_RESENT_DATE, /* Resent-Date */ 284 MAILIMF_FIELD_RESENT_FROM, /* Resent-From */ 285 MAILIMF_FIELD_RESENT_SENDER, /* Resent-Sender */ 286 MAILIMF_FIELD_RESENT_TO, /* Resent-To */ 287 MAILIMF_FIELD_RESENT_CC, /* Resent-Cc */ 288 MAILIMF_FIELD_RESENT_BCC, /* Resent-Bcc */ 289 MAILIMF_FIELD_RESENT_MSG_ID, /* Resent-Message-ID */ 290 MAILIMF_FIELD_ORIG_DATE, /* Date */ 291 MAILIMF_FIELD_FROM, /* From */ 292 MAILIMF_FIELD_SENDER, /* Sender */ 293 MAILIMF_FIELD_REPLY_TO, /* Reply-To */ 294 MAILIMF_FIELD_TO, /* To */ 295 MAILIMF_FIELD_CC, /* Cc */ 296 MAILIMF_FIELD_BCC, /* Bcc */ 297 MAILIMF_FIELD_MESSAGE_ID, /* Message-ID */ 298 MAILIMF_FIELD_IN_REPLY_TO, /* In-Reply-To */ 299 MAILIMF_FIELD_REFERENCES, /* References */ 300 MAILIMF_FIELD_SUBJECT, /* Subject */ 301 MAILIMF_FIELD_COMMENTS, /* Comments */ 302 MAILIMF_FIELD_KEYWORDS, /* Keywords */ 303 MAILIMF_FIELD_OPTIONAL_FIELD, /* other field */ 304 }; 305 306 /* 307 mailimf_field is a field 308 309 - type is the type of the field 310 311 - return_path is the parsed content of the Return-Path field if type is 312 MAILIMF_FIELD_RETURN_PATH 313 314 - resent_date is the parsed content of the Resent-Date field if type is 315 MAILIMF_FIELD_RESENT_DATE 316 317 - resent_from is the parsed content of the Resent-From field 318 319 - resent_sender is the parsed content of the Resent-Sender field 320 321 - resent_to is the parsed content of the Resent-To field 322 323 - resent_cc is the parsed content of the Resent-Cc field 324 325 - resent_bcc is the parsed content of the Resent-Bcc field 326 327 - resent_msg_id is the parsed content of the Resent-Message-ID field 328 329 - orig_date is the parsed content of the Date field 330 331 - from is the parsed content of the From field 332 333 - sender is the parsed content of the Sender field 334 335 - reply_to is the parsed content of the Reply-To field 336 337 - to is the parsed content of the To field 338 339 - cc is the parsed content of the Cc field 340 341 - bcc is the parsed content of the Bcc field 342 343 - message_id is the parsed content of the Message-ID field 344 345 - in_reply_to is the parsed content of the In-Reply-To field 346 347 - references is the parsed content of the References field 348 349 - subject is the content of the Subject field 350 351 - comments is the content of the Comments field 352 353 - keywords is the parsed content of the Keywords field 354 355 - optional_field is an other field and is not parsed 356 */ 357 358 #define LIBETPAN_MAILIMF_FIELD_UNION 359 360 struct mailimf_field { 361 int fld_type; 362 union { 363 struct mailimf_return * fld_return_path; /* can be NULL */ 364 struct mailimf_orig_date * fld_resent_date; /* can be NULL */ 365 struct mailimf_from * fld_resent_from; /* can be NULL */ 366 struct mailimf_sender * fld_resent_sender; /* can be NULL */ 367 struct mailimf_to * fld_resent_to; /* can be NULL */ 368 struct mailimf_cc * fld_resent_cc; /* can be NULL */ 369 struct mailimf_bcc * fld_resent_bcc; /* can be NULL */ 370 struct mailimf_message_id * fld_resent_msg_id; /* can be NULL */ 371 struct mailimf_orig_date * fld_orig_date; /* can be NULL */ 372 struct mailimf_from * fld_from; /* can be NULL */ 373 struct mailimf_sender * fld_sender; /* can be NULL */ 374 struct mailimf_reply_to * fld_reply_to; /* can be NULL */ 375 struct mailimf_to * fld_to; /* can be NULL */ 376 struct mailimf_cc * fld_cc; /* can be NULL */ 377 struct mailimf_bcc * fld_bcc; /* can be NULL */ 378 struct mailimf_message_id * fld_message_id; /* can be NULL */ 379 struct mailimf_in_reply_to * fld_in_reply_to; /* can be NULL */ 380 struct mailimf_references * fld_references; /* can be NULL */ 381 struct mailimf_subject * fld_subject; /* can be NULL */ 382 struct mailimf_comments * fld_comments; /* can be NULL */ 383 struct mailimf_keywords * fld_keywords; /* can be NULL */ 384 struct mailimf_optional_field * fld_optional_field; /* can be NULL */ 385 } fld_data; 386 }; 387 388 struct mailimf_field * 389 mailimf_field_new(int fld_type, 390 struct mailimf_return * fld_return_path, 391 struct mailimf_orig_date * fld_resent_date, 392 struct mailimf_from * fld_resent_from, 393 struct mailimf_sender * fld_resent_sender, 394 struct mailimf_to * fld_resent_to, 395 struct mailimf_cc * fld_resent_cc, 396 struct mailimf_bcc * fld_resent_bcc, 397 struct mailimf_message_id * fld_resent_msg_id, 398 struct mailimf_orig_date * fld_orig_date, 399 struct mailimf_from * fld_from, 400 struct mailimf_sender * fld_sender, 401 struct mailimf_reply_to * fld_reply_to, 402 struct mailimf_to * fld_to, 403 struct mailimf_cc * fld_cc, 404 struct mailimf_bcc * fld_bcc, 405 struct mailimf_message_id * fld_message_id, 406 struct mailimf_in_reply_to * fld_in_reply_to, 407 struct mailimf_references * fld_references, 408 struct mailimf_subject * fld_subject, 409 struct mailimf_comments * fld_comments, 410 struct mailimf_keywords * fld_keywords, 411 struct mailimf_optional_field * fld_optional_field); 412 413 void mailimf_field_free(struct mailimf_field * field); 414 415 416 417 /* 418 mailimf_orig_date is the parsed Date field 419 420 - date_time is the parsed date 421 */ 422 423 struct mailimf_orig_date { 424 struct mailimf_date_time * dt_date_time; /* != NULL */ 425 }; 426 427 struct mailimf_orig_date * mailimf_orig_date_new(struct mailimf_date_time * 428 dt_date_time); 429 430 void mailimf_orig_date_free(struct mailimf_orig_date * orig_date); 431 432 433 434 435 /* 436 mailimf_from is the parsed From field 437 438 - mb_list is the parsed mailbox list 439 */ 440 441 struct mailimf_from { 442 struct mailimf_mailbox_list * frm_mb_list; /* != NULL */ 443 }; 444 445 struct mailimf_from * 446 mailimf_from_new(struct mailimf_mailbox_list * frm_mb_list); 447 448 void mailimf_from_free(struct mailimf_from * from); 449 450 451 452 /* 453 mailimf_sender is the parsed Sender field 454 455 - mb is the parsed mailbox 456 */ 457 458 struct mailimf_sender { 459 struct mailimf_mailbox * snd_mb; /* != NULL */ 460 }; 461 462 struct mailimf_sender * mailimf_sender_new(struct mailimf_mailbox * snd_mb); 463 464 void mailimf_sender_free(struct mailimf_sender * sender); 465 466 467 468 469 /* 470 mailimf_reply_to is the parsed Reply-To field 471 472 - addr_list is the parsed address list 473 */ 474 475 struct mailimf_reply_to { 476 struct mailimf_address_list * rt_addr_list; /* != NULL */ 477 }; 478 479 struct mailimf_reply_to * 480 mailimf_reply_to_new(struct mailimf_address_list * rt_addr_list); 481 482 void mailimf_reply_to_free(struct mailimf_reply_to * reply_to); 483 484 485 486 487 /* 488 mailimf_to is the parsed To field 489 490 - addr_list is the parsed address list 491 */ 492 493 struct mailimf_to { 494 struct mailimf_address_list * to_addr_list; /* != NULL */ 495 }; 496 497 struct mailimf_to * mailimf_to_new(struct mailimf_address_list * to_addr_list); 498 499 void mailimf_to_free(struct mailimf_to * to); 500 501 502 503 504 /* 505 mailimf_cc is the parsed Cc field 506 507 - addr_list is the parsed addres list 508 */ 509 510 struct mailimf_cc { 511 struct mailimf_address_list * cc_addr_list; /* != NULL */ 512 }; 513 514 struct mailimf_cc * mailimf_cc_new(struct mailimf_address_list * cc_addr_list); 515 516 void mailimf_cc_free(struct mailimf_cc * cc); 517 518 519 520 521 /* 522 mailimf_bcc is the parsed Bcc field 523 524 - addr_list is the parsed addres list 525 */ 526 527 struct mailimf_bcc { 528 struct mailimf_address_list * bcc_addr_list; /* can be NULL */ 529 }; 530 531 struct mailimf_bcc * 532 mailimf_bcc_new(struct mailimf_address_list * bcc_addr_list); 533 534 void mailimf_bcc_free(struct mailimf_bcc * bcc); 535 536 537 538 /* 539 mailimf_message_id is the parsed Message-ID field 540 541 - value is the message identifier 542 */ 543 544 struct mailimf_message_id { 545 char * mid_value; /* != NULL */ 546 }; 547 548 struct mailimf_message_id * mailimf_message_id_new(char * mid_value); 549 550 void mailimf_message_id_free(struct mailimf_message_id * message_id); 551 552 553 554 555 /* 556 mailimf_in_reply_to is the parsed In-Reply-To field 557 558 - msg_id_list is the list of message identifers 559 */ 560 561 struct mailimf_in_reply_to { 562 clist * mid_list; /* list of (char *) */ 563 /* != NULL */ 564 }; 565 566 struct mailimf_in_reply_to * mailimf_in_reply_to_new(clist * mid_list); 567 568 void mailimf_in_reply_to_free(struct mailimf_in_reply_to * in_reply_to); 569 570 571 572 /* 573 mailimf_references is the parsed References field 574 575 - msg_id_list is the list of message identifiers 576 */ 577 578 struct mailimf_references { 579 clist * mid_list; /* list of (char *) */ 580 /* != NULL */ 581 }; 582 583 struct mailimf_references * mailimf_references_new(clist * mid_list); 584 585 void mailimf_references_free(struct mailimf_references * references); 586 587 588 589 /* 590 mailimf_subject is the parsed Subject field 591 592 - value is the value of the field 593 */ 594 595 struct mailimf_subject { 596 char * sbj_value; /* != NULL */ 597 }; 598 599 struct mailimf_subject * mailimf_subject_new(char * sbj_value); 600 601 void mailimf_subject_free(struct mailimf_subject * subject); 602 603 604 /* 605 mailimf_comments is the parsed Comments field 606 607 - value is the value of the field 608 */ 609 610 struct mailimf_comments { 611 char * cm_value; /* != NULL */ 612 }; 613 614 struct mailimf_comments * mailimf_comments_new(char * cm_value); 615 616 void mailimf_comments_free(struct mailimf_comments * comments); 617 618 619 /* 620 mailimf_keywords is the parsed Keywords field 621 622 - list is the list of keywords 623 */ 624 625 struct mailimf_keywords { 626 clist * kw_list; /* list of (char *) */ 627 /* != NULL */ 628 }; 629 630 struct mailimf_keywords * mailimf_keywords_new(clist * kw_list); 631 632 void mailimf_keywords_free(struct mailimf_keywords * keywords); 633 634 635 /* 636 mailimf_return is the parsed Return-Path field 637 638 - path is the parsed value of Return-Path 639 */ 640 641 struct mailimf_return { 642 struct mailimf_path * ret_path; /* != NULL */ 643 }; 644 645 struct mailimf_return * 646 mailimf_return_new(struct mailimf_path * ret_path); 647 648 void mailimf_return_free(struct mailimf_return * return_path); 649 650 651 /* 652 mailimf_path is the parsed value of Return-Path 653 654 - addr_spec is a mailbox 655 */ 656 657 struct mailimf_path { 658 char * pt_addr_spec; /* can be NULL */ 659 }; 660 661 struct mailimf_path * mailimf_path_new(char * pt_addr_spec); 662 663 void mailimf_path_free(struct mailimf_path * path); 664 665 666 /* 667 mailimf_optional_field is a non-parsed field 668 669 - name is the name of the field 670 671 - value is the value of the field 672 */ 673 674 struct mailimf_optional_field { 675 char * fld_name; /* != NULL */ 676 char * fld_value; /* != NULL */ 677 }; 678 679 struct mailimf_optional_field * 680 mailimf_optional_field_new(char * fld_name, char * fld_value); 681 682 void mailimf_optional_field_free(struct mailimf_optional_field * opt_field); 683 684 685 /* 686 mailimf_fields is the native structure that IMF module will use, 687 this module will provide an easier structure to use when parsing fields. 688 689 mailimf_single_fields is an easier structure to get parsed fields, 690 rather than iteration over the list of fields 691 692 - orig_date is the parsed "Date" field 693 694 - from is the parsed "From" field 695 696 - sender is the parsed "Sender "field 697 698 - reply_to is the parsed "Reply-To" field 699 700 - to is the parsed "To" field 701 702 - cc is the parsed "Cc" field 703 704 - bcc is the parsed "Bcc" field 705 706 - message_id is the parsed "Message-ID" field 707 708 - in_reply_to is the parsed "In-Reply-To" field 709 710 - references is the parsed "References" field 711 712 - subject is the parsed "Subject" field 713 714 - comments is the parsed "Comments" field 715 716 - keywords is the parsed "Keywords" field 717 */ 718 719 struct mailimf_single_fields { 720 struct mailimf_orig_date * fld_orig_date; /* can be NULL */ 721 struct mailimf_from * fld_from; /* can be NULL */ 722 struct mailimf_sender * fld_sender; /* can be NULL */ 723 struct mailimf_reply_to * fld_reply_to; /* can be NULL */ 724 struct mailimf_to * fld_to; /* can be NULL */ 725 struct mailimf_cc * fld_cc; /* can be NULL */ 726 struct mailimf_bcc * fld_bcc; /* can be NULL */ 727 struct mailimf_message_id * fld_message_id; /* can be NULL */ 728 struct mailimf_in_reply_to * fld_in_reply_to; /* can be NULL */ 729 struct mailimf_references * fld_references; /* can be NULL */ 730 struct mailimf_subject * fld_subject; /* can be NULL */ 731 struct mailimf_comments * fld_comments; /* can be NULL */ 732 struct mailimf_keywords * fld_keywords; /* can be NULL */ 733 }; 734 735 736 737 738 739 740 /* internal use */ 741 742 void mailimf_atom_free(char * atom); 743 744 void mailimf_dot_atom_free(char * dot_atom); 745 746 void mailimf_dot_atom_text_free(char * dot_atom); 747 748 void mailimf_quoted_string_free(char * quoted_string); 749 750 void mailimf_word_free(char * word); 751 752 void mailimf_phrase_free(char * phrase); 753 754 void mailimf_unstructured_free(char * unstructured); 755 756 void mailimf_angle_addr_free(char * angle_addr); 757 758 void mailimf_display_name_free(char * display_name); 759 760 void mailimf_addr_spec_free(char * addr_spec); 761 762 void mailimf_local_part_free(char * local_part); 763 764 void mailimf_domain_free(char * domain); 765 766 void mailimf_domain_literal_free(char * domain); 767 768 void mailimf_msg_id_free(char * msg_id); 769 770 void mailimf_id_left_free(char * id_left); 771 772 void mailimf_id_right_free(char * id_right); 773 774 void mailimf_no_fold_quote_free(char * nfq); 775 776 void mailimf_no_fold_literal_free(char * nfl); 777 778 void mailimf_field_name_free(char * field_name); 779 780 781 782 /* these are the possible returned error codes */ 783 784 enum { 785 MAILIMF_NO_ERROR = 0, 786 MAILIMF_ERROR_PARSE, 787 MAILIMF_ERROR_MEMORY, 788 MAILIMF_ERROR_INVAL, 789 MAILIMF_ERROR_FILE, 790 }; 791 792 793 #ifdef __cplusplus 794 } 795 #endif 796 797 #endif 798