ircrequestparser.cpp
1 //------------------------------------------------------------------------------
2 // ircrequestparser.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 
22 // Copyright (C) 2010 "Zalewa" <zalewapl@gmail.com>
23 //------------------------------------------------------------------------------
24 #include "irc/ircadapterbase.h"
25 #include "irc/ircclient.h"
26 #include "irc/ircctcpparser.h"
27 #include "irc/ircglobal.h"
28 #include "irc/ircmessageclass.h"
29 #include "irc/ircnetworkadapter.h"
30 #include "irc/ircuserinfo.h"
31 #include "ircrequestparser.h"
32 #include <QStringList>
33 
34 DClass<IRCRequestParser>
35 {
36 public:
37  IRCAdapterBase *adapter;
38  QString output;
39  QString message;
40  QStringList tokens;
41 };
42 
43 DPointered(IRCRequestParser)
44 
46 {
47  d->adapter = nullptr;
48 }
49 
50 IRCRequestParser::~IRCRequestParser()
51 {
52 }
53 
54 IRCNetworkAdapter *IRCRequestParser::network()
55 {
56  return d->adapter->network();
57 }
58 
59 const QString &IRCRequestParser::output() const
60 {
61  return d->output;
62 }
63 
64 IRCRequestParser::IRCRequestParseResult IRCRequestParser::parse(IRCAdapterBase *pAdapter, QString input)
65 {
66  d->adapter = pAdapter;
67  d->output.clear();
68  d->tokens.clear();
69  d->message.clear();
70 
71  input = input.trimmed();
72 
73  if (input.isEmpty())
74  return ErrorMessageEmpty;
75 
76  if (input[0] != '/')
77  return ErrorInputNotPrependedWithSlash;
78 
79  input.remove(0, 1);
80  if (input.isEmpty())
81  return ErrorMessageEmpty;
82 
83  QStringList inputSplit = input.split(" ", Qt::SkipEmptyParts);
84  d->message = inputSplit.takeFirst().toUpper();
85  d->tokens = inputSplit;
86 
87  IRCRequestParser::IRCRequestParseResult result = buildOutput();
88  if (result == Ok)
89  {
90  if (isOutputTooLong())
91  return ErrorMessageTooLong;
92  }
93 
94  return result;
95 }
96 
97 IRCRequestParser::IRCRequestParseResult IRCRequestParser::buildOutput()
98 {
99  if (d->message == "QUIT")
100  {
101  d->output = QString("%1 :%2").arg(d->message, d->tokens.join(" "));
102  return QuitCommand;
103  }
104  else if (d->message == "AWAY")
105  d->output = QString("%1 :%2").arg(d->message, d->tokens.join(" "));
106  else if (d->message == "PART")
107  {
108  if (d->tokens.isEmpty())
109  return ErrorInputInsufficientParameters;
110 
111  QString channel = d->tokens.takeFirst();
112  QString farewellMessage = d->tokens.join(" ");
113  d->output = QString("%1 %2 :%3").arg(d->message, channel, farewellMessage);
114  }
115  else if (d->message == "KICK")
116  {
117  if (d->tokens.length() < 2)
118  return ErrorInputInsufficientParameters;
119 
120  QString channel = d->tokens.takeFirst();
121  QString user = d->tokens.takeFirst();
122  QString reason = d->tokens.join(" ");
123  d->output = QString("%1 %2 %3 :%4").arg(d->message, channel, user, reason);
124  }
125  else if (d->message == "PRIVMSG" || d->message == "NOTICE")
126  {
127  // Notice and Privmsg are handled the same way.
128  if (d->tokens.length() < 2)
129  return ErrorInputInsufficientParameters;
130 
131  QString recipient = d->tokens.takeFirst();
132  QString content = d->tokens.join(" ");
133  d->output = QString("%1 %2 :%3").arg(d->message, recipient, content);
134  if (isOutputTooLong())
135  {
136  // If message is too long at this point for some reason,
137  // we should prevent echoing it back to the chat window as that
138  // confuses the user as to whether the message was sent or not.
139  return ErrorMessageTooLong;
140  }
141  if (d->message == "PRIVMSG")
142  {
143  IRCCtcpParser ctcp(network(), network()->myNickname(),
144  recipient, content, IRCCtcpParser::Request);
145  if (ctcp.parse())
146  {
147  switch (ctcp.echo())
148  {
149  case IRCCtcpParser::PrintAsNormalMessage:
150  network()->printMsgLiteral(recipient, ctcp.printable(), IRCMessageClass::Ctcp);
151  break;
152  case IRCCtcpParser::DisplayInServerTab:
153  network()->printWithClass(ctcp.printable(), QString(), IRCMessageClass::Ctcp);
154  break;
155  case IRCCtcpParser::DisplayThroughGlobalMessage:
156  network()->printToCurrentChatBox(ctcp.printable(), IRCMessageClass::Ctcp);
157  break;
158  case IRCCtcpParser::DontShow:
159  break;
160  }
161  }
162  else
163  emit echoPrivmsg(recipient, content);
164  }
165  }
166  else if (d->message == "MSG")
167  {
168  // This is an alias to the PRIVMSG command but it is so popular
169  // that I decided to implement this permanently.
170  parse(d->adapter, QString("/PRIVMSG %1").arg(d->tokens.join(" ")));
171  }
172  else if (d->message == "QUERY")
173  {
174  if (!d->tokens.isEmpty())
175  {
176  QString recipient = d->tokens.takeFirst();
177  if (!IRCGlobal::isChannelName(recipient))
178  {
179  IRCUserInfo userInfo(recipient, d->adapter->network());
180  emit query(userInfo.cleanNickname());
181  }
182  }
183  }
184  else if (d->message == "ME")
185  {
186  QString recipient = d->adapter->recipient();
187  if (recipient.isEmpty())
188  return ErrorChatWindowOnly;
189  QString content = d->tokens.join(" ");
190  parse(d->adapter, QString("/PRIVMSG %1 %2ACTION %3%2").arg(recipient, QChar(0x1), content));
191  }
192  else
193  d->output = QString("%1 %2").arg(d->message, d->tokens.join(" "));
194 
195  return Ok;
196 }
197 
198 bool IRCRequestParser::isOutputTooLong() const
199 {
200  return d->output.toUtf8().length() > IRCClient::MAX_MESSAGE_LENGTH;
201 }