File indexing completed on 2024-09-22 04:52:51

0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
0002 
0003    This file is part of the Trojita Qt IMAP e-mail client,
0004    http://trojita.flaska.net/
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include <QDebug>
0024 #include "Imap/Parser/Rfc5322HeaderParser.h"
0025 
0026 #define DBG(X) do {qDebug() << X << "(current char:" << *p << ")";} while(false);
0027 //#define RAGEL_DEBUG
0028 
0029 namespace Imap {
0030 namespace LowLevelParser {
0031 
0032 %%{
0033     machine rfc5322;
0034 
0035     action push_current_char {
0036 #ifdef RAGEL_DEBUG
0037         qDebug() << "push_current_char " << *p;
0038 #endif
0039         str.append(*p);
0040     }
0041 
0042     action clear_str {
0043 #ifdef RAGEL_DEBUG
0044         qDebug() << "clear_str";
0045 #endif
0046         str.clear();
0047     }
0048 
0049     action push_current_backslashed {
0050         switch (*p) {
0051             case 'n':
0052                 str += "\n";
0053                 break;
0054             case 'r':
0055                 str += "\r";
0056                 break;
0057             case '0':
0058                 str += "\0";
0059                 break;
0060             case '\\':
0061                 str += "\\";
0062                 break;
0063             default:
0064                 str += '\\' + *p;
0065         }
0066 #ifdef RAGEL_DEBUG
0067         qDebug() << "push_current_backslashed \\" << *p;
0068 #endif
0069     }
0070 
0071     action push_string_list {
0072 #ifdef RAGEL_DEBUG
0073         qDebug() << "push_string_list " << str.data();
0074 #endif
0075         list.append(str);
0076         str.clear();
0077     }
0078 
0079     action clear_list {
0080 #ifdef RAGEL_DEBUG
0081         qDebug() << "clear_list";
0082 #endif
0083         list.clear();
0084         str.clear();
0085     }
0086 
0087     action got_message_id_header {
0088         if (list.size() == 1) {
0089 #ifdef RAGEL_DEBUG
0090             qDebug() << "Message-Id: " << list[0].data();
0091 #endif
0092             messageId += list;
0093         } else {
0094 #ifdef RAGEL_DEBUG
0095             qDebug() << "invalid Message-Id";
0096 #endif
0097         }
0098     }
0099 
0100     action got_in_reply_to_header {
0101         inReplyTo += list;
0102 #ifdef RAGEL_DEBUG
0103         qDebug() << "In-Reply-To: " << list;
0104 #endif
0105     }
0106 
0107     action got_references_header {
0108         references += list;
0109 #ifdef RAGEL_DEBUG
0110         qDebug() << "got_references_header:" << references;
0111 #endif
0112     }
0113 
0114     action got_list_post_header {
0115         listPost += list;
0116 #ifdef RAGEL_DEBUG
0117         qDebug() << "got_list_post_header:" << listPost;
0118 #endif
0119     }
0120 
0121     action got_list_post_no {
0122         listPostNo = true;
0123 #ifdef RAGEL_DEBUG
0124         qDebug() << "got_list_post_no";
0125 #endif
0126     }
0127 
0128     action header_error {
0129 #ifdef RAGEL_DEBUG
0130         qDebug() << "Error when parsing RFC5322 headers";
0131 #endif
0132         m_error = true;
0133     }
0134 
0135 
0136     include rfc5322 "rfc5322.rl";
0137 
0138     main := ( optional_field | references | obs_references | list_post | message_id | obs_message_id
0139         | in_reply_to | obs_in_reply_to)* @err(header_error) CRLF*;
0140 }%%
0141 
0142 #ifdef __clang__
0143 #pragma clang diagnostic push
0144 #if defined(__has_warning) && __has_warning("-Wunused-const-variable")
0145 #pragma clang diagnostic ignored "-Wunused-const-variable"
0146 #endif
0147 #endif
0148 %%{
0149     write data;
0150 }%%
0151 #ifdef __clang__
0152 #pragma clang diagnostic pop
0153 #endif
0154 
0155 Rfc5322HeaderParser::Rfc5322HeaderParser():
0156     listPostNo(false), m_error(false)
0157 {
0158 }
0159 
0160 void Rfc5322HeaderParser::clear()
0161 {
0162     m_error = false;
0163     references.clear();
0164     listPost.clear();
0165     messageId.clear();
0166     inReplyTo.clear();
0167     listPostNo = false;
0168 }
0169 
0170 bool Rfc5322HeaderParser::parse(const QByteArray &data)
0171 {
0172     clear();
0173 
0174     const char *p = data.constData();
0175     const char *pe = p + data.length();
0176     const char *eof = pe;
0177     int cs;
0178 
0179     QByteArray str;
0180     QList<QByteArray> list;
0181 
0182     %% write init;
0183     %% write exec;
0184 
0185     return !m_error;
0186 }
0187 
0188 }
0189 }
0190 
0191 #if 0
0192 #include <iostream>
0193 int main()
0194 {
0195     QByteArray data;
0196     std::string line;
0197 
0198     while (std::getline(std::cin, line)) {
0199         data += line.c_str();
0200         data += '\n';
0201     }
0202 
0203     Imap::Parser::Rfc5322HeaderParser parser;
0204     bool res = parser.parse(data);
0205     if (!res) {
0206         qDebug() << "Parsing error.";
0207         return 1;
0208     }
0209 
0210     qDebug() << "References:" << parser.references;
0211 
0212     return 0;
0213 }
0214 #endif