Implement IRCv3 tag parsing and sending
[quassel.git] / src / common / ircencoder.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2019 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "ircencoder.h"
22
23 QByteArray IrcEncoder::writeMessage(const QHash<IrcTagKey, QString>& tags,
24                                    const QByteArray& prefix,
25                                    const QString& cmd,
26                                    const QList<QByteArray>& params)
27 {
28     QByteArray msg;
29     writeTags(msg, tags);
30     writePrefix(msg, prefix);
31     writeCommand(msg, cmd);
32     writeParams(msg, params);
33     return msg;
34 }
35
36 void IrcEncoder::writeTagValue(QByteArray& msg, const QString& value)
37 {
38     QString it = value;
39     msg += it.replace("\\", R"(\\)")
40              .replace(";", R"(\:)")
41              .replace(" ", R"(\s)")
42              .replace("\r", R"(\r)")
43              .replace("\n", R"(\n)");
44 }
45
46 void IrcEncoder::writeTags(QByteArray& msg, const QHash<IrcTagKey, QString>& tags)
47 {
48     if (!tags.isEmpty()) {
49         msg += "@";
50         bool isFirstTag = true;
51         for (const IrcTagKey& key : tags.keys()) {
52             if (!isFirstTag) {
53                 // We join tags with semicolons
54                 msg += ";";
55             }
56             if (key.clientTag) {
57                 msg += "+";
58             }
59             if (!key.vendor.isEmpty()) {
60                 msg += key.vendor;
61                 msg += "/";
62             }
63             msg += key.key;
64             if (!tags[key].isEmpty()) {
65                 msg += "=";
66                 writeTagValue(msg, tags[key]);
67             }
68
69             isFirstTag = false;
70         }
71         msg += " ";
72     }
73 }
74
75 void IrcEncoder::writePrefix(QByteArray& msg, const QByteArray& prefix)
76 {
77     if (!prefix.isEmpty()) {
78         msg += ":" + prefix + " ";
79     }
80 }
81
82 void IrcEncoder::writeCommand(QByteArray& msg, const QString& cmd)
83 {
84     msg += cmd.toUpper().toLatin1();
85 }
86
87 void IrcEncoder::writeParams(QByteArray& msg, const QList<QByteArray>& params)
88 {
89     for (int i = 0; i < params.size(); i++) {
90         msg += " ";
91
92         bool isLastParam = i == params.size() - 1;
93         if (isLastParam && (params[i].isEmpty() || params[i].contains(' ') || params[i][0] == ':'))
94             msg += ":";
95
96         msg += params[i];
97     }
98 }