ircrequestparser.cpp
1 //------------------------------------------------------------------------------
2 // ircrequestparser.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
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 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 "ircrequestparser.h"
25 #include "irc/ircadapterbase.h"
26 #include "irc/ircclient.h"
27 #include "irc/ircctcpparser.h"
28 #include "irc/ircglobal.h"
29 #include "irc/ircmessageclass.h"
30 #include "irc/ircnetworkadapter.h"
31 #include "irc/ircuserinfo.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 = NULL;
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  {
75  return ErrorMessageEmpty;
76  }
77 
78  if (input[0] != '/')
79  {
80  return ErrorInputNotPrependedWithSlash;
81  }
82 
83  input.remove(0, 1);
84  if (input.isEmpty())
85  {
86  return ErrorMessageEmpty;
87  }
88 
89  QStringList inputSplit = input.split(" ", QString::SkipEmptyParts);
90  d->message = inputSplit.takeFirst().toUpper();
91  d->tokens = inputSplit;
92 
93  IRCRequestParser::IRCRequestParseResult result = buildOutput();
94  if (result == Ok)
95  {
96  if (isOutputTooLong())
97  {
98  return ErrorMessageTooLong;
99  }
100  }
101 
102  return result;
103 }
104 
105 IRCRequestParser::IRCRequestParseResult IRCRequestParser::buildOutput()
106 {
107  if (d->message == "QUIT")
108  {
109  d->output = QString("%1 :%2").arg(d->message, d->tokens.join(" "));
110  return QuitCommand;
111  }
112  else if (d->message == "AWAY")
113  {
114  d->output = QString("%1 :%2").arg(d->message, d->tokens.join(" "));
115  }
116  else if (d->message == "PART")
117  {
118  if (d->tokens.isEmpty())
119  {
120  return ErrorInputInsufficientParameters;
121  }
122 
123  QString channel = d->tokens.takeFirst();
124  QString farewellMessage = d->tokens.join(" ");
125  d->output = QString("%1 %2 :%3").arg(d->message, channel, farewellMessage);
126  }
127  else if (d->message == "KICK")
128  {
129  if (d->tokens.length() < 2)
130  {
131  return ErrorInputInsufficientParameters;
132  }
133 
134  QString channel = d->tokens.takeFirst();
135  QString user = d->tokens.takeFirst();
136  QString reason = d->tokens.join(" ");
137  d->output = QString("%1 %2 %3 :%4").arg(d->message, channel, user, reason);
138  }
139  else if (d->message == "PRIVMSG" || d->message == "NOTICE")
140  {
141  // Notice and Privmsg are handled the same way.
142  if (d->tokens.length() < 2)
143  {
144  return ErrorInputInsufficientParameters;
145  }
146 
147  QString recipient = d->tokens.takeFirst();
148  QString content = d->tokens.join(" ");
149  d->output = QString("%1 %2 :%3").arg(d->message, recipient, content);
150  if (isOutputTooLong())
151  {
152  // If message is too long at this point for some reason,
153  // we should prevent echoing it back to the chat window as that
154  // confuses the user as to whether the message was sent or not.
155  return ErrorMessageTooLong;
156  }
157  if (d->message == "PRIVMSG")
158  {
159  IRCCtcpParser ctcp(network(), network()->myNickname(),
160  recipient, content, IRCCtcpParser::Request);
161  if (ctcp.parse())
162  {
163  switch (ctcp.echo())
164  {
165  case IRCCtcpParser::PrintAsNormalMessage:
166  network()->printMsgLiteral(recipient, ctcp.printable(), IRCMessageClass::Ctcp);
167  break;
168  case IRCCtcpParser::DisplayInServerTab:
169  network()->printWithClass(ctcp.printable(), QString(), IRCMessageClass::Ctcp);
170  break;
171  case IRCCtcpParser::DisplayThroughGlobalMessage:
172  network()->printToCurrentChatBox(ctcp.printable(), IRCMessageClass::Ctcp);
173  break;
174  case IRCCtcpParser::DontShow:
175  break;
176  }
177  }
178  else
179  {
180  emit echoPrivmsg(recipient, content);
181  }
182  }
183  }
184  else if (d->message == "MSG")
185  {
186  // This is an alias to the PRIVMSG command but it is so popular
187  // that I decided to implement this permanently.
188  parse(d->adapter, QString("/PRIVMSG %1").arg(d->tokens.join(" ")));
189  }
190  else if (d->message == "QUERY")
191  {
192  if (!d->tokens.isEmpty())
193  {
194  QString recipient = d->tokens.takeFirst();
195  if (!IRCGlobal::isChannelName(recipient))
196  {
197  IRCUserInfo userInfo(recipient, d->adapter->network());
198  emit query(userInfo.cleanNickname());
199  }
200  }
201  }
202  else if (d->message == "ME")
203  {
204  QString recipient = d->adapter->recipient();
205  if (recipient.isEmpty())
206  {
207  return ErrorChatWindowOnly;
208  }
209  QString content = d->tokens.join(" ");
210  parse(d->adapter, QString("/PRIVMSG %1 %2ACTION %3%2").arg(recipient, QChar(0x1), content));
211  }
212  else
213  {
214  d->output = QString("%1 %2").arg(d->message, d->tokens.join(" "));
215  }
216 
217  return Ok;
218 }
219 
220 bool IRCRequestParser::isOutputTooLong() const
221 {
222  return d->output.toUtf8().length() > IRCClient::MAX_MESSAGE_LENGTH;
223 }
224 
Interprets communication between the client and the IRC server.
Parses request and interprets them in a way that emulates mIRC (or any even slightly sane IRC client ...
Provides an unified communication interface between a client and IRC network entities.
void query(const QString &who)
Emitted when "/query" alias is used.
IRCRequestParseResult parse(IRCAdapterBase *pAdapter, QString input)
Parses input string and returns it through output string. Additional information is passed through re...
A question is being asked through PRIVMSG.
Definition: ircctcpparser.h:29
void echoPrivmsg(const QString &recipient, const QString &content)
Echoes back all PRIVMSG commands.
Holds information flags about given nickname.
Definition: ircuserinfo.h:35