~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/modules/options/OptionsWidget_connection.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=============================================================================
 
2
//
 
3
//   File : OptionsWidget_connection.cpp
 
4
//   Creation date : Sat Nov 24 04:25:16 2001 GMT by Szymon Stefanek
 
5
//
 
6
//   This file is part of the KVIrc irc client distribution
 
7
//   Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net)
 
8
//   copyright (C) 2008 Elvio Basello (hellvis69 at netsons dot org)
 
9
//
 
10
//   This program is FREE software. You can redistribute it and/or
 
11
//   modify it under the terms of the GNU General Public License
 
12
//   as published by the Free Software Foundation; either version 2
 
13
//   of the License, or (at your opinion) any later version.
 
14
//
 
15
//   This program is distributed in the HOPE that it will be USEFUL,
 
16
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
18
//   See the GNU General Public License for more details.
 
19
//
 
20
//   You should have received a copy of the GNU General Public License
 
21
//   along with this program. If not, write to the Free Software Foundation,
 
22
//   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
23
//
 
24
//=============================================================================
 
25
 
 
26
#include "OptionsWidget_connection.h"
 
27
 
 
28
#include "kvi_settings.h"
 
29
#include "KviLocale.h"
 
30
#include "KviOptions.h"
 
31
#include "KviIconManager.h"
 
32
 
 
33
#include <QRadioButton>
 
34
 
 
35
 
 
36
OptionsWidget_connection::OptionsWidget_connection(QWidget * parent)
 
37
: KviOptionsWidget(parent)
 
38
{
 
39
        setObjectName("connection_options_widget");
 
40
        createLayout();
 
41
        KviTalGroupBox *gbox = addGroupBox(0,0,0,0,Qt::Horizontal,__tr2qs_ctx("On Disconnect","options"));
 
42
 
 
43
        KviBoolSelector *b1 = addBoolSelector(gbox,__tr2qs_ctx("Keep channels open","options"),KviOption_boolKeepChannelsOpenOnDisconnect,true);
 
44
        mergeTip(b1,__tr2qs_ctx("<center>This option will cause KVIrc to keep channels open after disconnect.</center>","options"));
 
45
 
 
46
        b1 = addBoolSelector(gbox,__tr2qs_ctx("Keep queries open","options"),KviOption_boolKeepQueriesOpenOnDisconnect,true);
 
47
        mergeTip(b1,__tr2qs_ctx("<center>This option will cause KVIrc to keep queries open after disconnect.</center>","options"));
 
48
 
 
49
        gbox = addGroupBox(0,1,0,1,Qt::Horizontal,__tr2qs_ctx("On Unexpected Disconnect","options"));
 
50
 
 
51
        b1 = addBoolSelector(gbox,__tr2qs_ctx("Keep channels open","options"),KviOption_boolKeepChannelsOpenOnUnexpectedDisconnect,true);
 
52
        mergeTip(b1,__tr2qs_ctx("<center>This option will cause KVIrc to keep channels open after an unexpected disconnect.</center>","options"));
 
53
 
 
54
        b1 = addBoolSelector(gbox,__tr2qs_ctx("Keep queries open","options"),KviOption_boolKeepQueriesOpenOnUnexpectedDisconnect,true);
 
55
        mergeTip(b1,__tr2qs_ctx("<center>This option will cause KVIrc to keep queries open after an unexpected disconnect.</center>","options"));
 
56
 
 
57
        b1 = addBoolSelector(gbox,__tr2qs_ctx("Rejoin channels after reconnect","options"),KviOption_boolRejoinChannelsAfterReconnect,KVI_OPTION_BOOL(KviOption_boolAutoReconnectOnUnexpectedDisconnect));
 
58
        mergeTip(b1,__tr2qs_ctx("<center>This option will cause KVIrc to rejoin channels after a successful reconnect attempt.</center>","options"));
 
59
 
 
60
        b1 = addBoolSelector(gbox,__tr2qs_ctx("Reopen queries after reconnect","options"),KviOption_boolReopenQueriesAfterReconnect,KVI_OPTION_BOOL(KviOption_boolAutoReconnectOnUnexpectedDisconnect));
 
61
        mergeTip(b1,__tr2qs_ctx("<center>This option will cause KVIrc to reopen query windows after a successful reconnect attempt.</center>","options"));
 
62
 
 
63
//      gbox = addGroupBox(0,1,0,1,Qt::Horizontal,__tr2qs_ctx("On Unexpected Disconnect","options"));
 
64
        KviBoolSelector * b = addBoolSelector(gbox,__tr2qs_ctx("Automatically reconnect","options"),KviOption_boolAutoReconnectOnUnexpectedDisconnect);
 
65
        mergeTip(b,__tr2qs_ctx("<center>This option will enable auto-reconnecting after an unexpected disconnect. " \
 
66
                "An unexpected disconnect is the <b>termination</b> of a <b>fully connected IRC session</b> " \
 
67
                "that was <b>not requested by the user</b> by the means of the QUIT message." \
 
68
                "<p><b>Warning:</b> If you use /RAW to send a QUIT message to the server, " \
 
69
                "this option will not behave correctly, since does not detect the outgoing " \
 
70
                "QUIT message and will attempt to reconnect after the server has closed the connection. " \
 
71
                "For this reason, always use the /QUIT command to close your connections. " \
 
72
                "This option may also behave incorrectly with bouncers that support " \
 
73
                "detaching, in this case a solution could be to prepare an alias that sends the " \
 
74
                "bouncer \"detach\" command immediately before the \"quit\" command.<br>" \
 
75
                "<tt>alias(bncdetach){ raw bouncer detach; quit; }</tt></p></center>","options"));
 
76
 
 
77
        KviUIntSelector * u = addUIntSelector(gbox,__tr2qs_ctx("Maximum attempts (0: unlimited):","options"),
 
78
                        KviOption_uintMaxAutoReconnectAttempts,0,100,5,
 
79
                        KVI_OPTION_BOOL(KviOption_boolAutoReconnectOnUnexpectedDisconnect));
 
80
        connect(b,SIGNAL(toggled(bool)),u,SLOT(setEnabled(bool)));
 
81
 
 
82
        u = addUIntSelector(gbox,__tr2qs_ctx("Delay between attempts:","options"),
 
83
                        KviOption_uintAutoReconnectDelay,0,86400,5,
 
84
                        KVI_OPTION_BOOL(KviOption_boolAutoReconnectOnUnexpectedDisconnect));
 
85
        u->setSuffix(__tr2qs_ctx(" sec","options"));
 
86
        connect(b,SIGNAL(toggled(bool)),u,SLOT(setEnabled(bool)));
 
87
        mergeTip(u,__tr2qs_ctx("<center>Minimum value: <b>0 sec</b><br>Maximum value: <b>86400 sec</b></center>","options"));
 
88
 
 
89
        b = addBoolSelector(this,__tr2qs_ctx("Use the SASL authentication protocol if available","options"),&(KVI_OPTION_BOOL(KviOption_boolUseSaslIfAvailable)),true);
 
90
        mergeTip(b,__tr2qs_ctx("<center>When available and enabled of the specific server, KVIrc will try to authenticate the user using the SASL procotol</center>","options"));
 
91
        addWidgetToLayout(b,0,2,0,2);
 
92
 
 
93
        addRowSpacer(0,3,4,3);
 
94
}
 
95
 
 
96
OptionsWidget_connection::~OptionsWidget_connection()
 
97
{
 
98
}
 
99
 
 
100
 
 
101
OptionsWidget_connectionSsl::OptionsWidget_connectionSsl(QWidget * parent)
 
102
: KviOptionsWidget(parent)
 
103
{
 
104
        setObjectName("ssl_options_widget");
 
105
        createLayout();
 
106
 
 
107
#ifdef COMPILE_SSL_SUPPORT
 
108
        KviTalGroupBox * gbox = addGroupBox(0,0,0,0,Qt::Horizontal,__tr2qs_ctx("Certificate","options"));
 
109
 
 
110
        KviBoolSelector * b = addBoolSelector(gbox,__tr2qs_ctx("Use SSL certificate (PEM format only)","options"),
 
111
                &(KVI_OPTION_BOOL(KviOption_boolUseSSLCertificate)),true);
 
112
        KviFileSelector * f = addFileSelector(gbox,__tr2qs_ctx("Certificate location:","options"),
 
113
                &(KVI_OPTION_STRING(KviOption_stringSSLCertificatePath)),KVI_OPTION_BOOL(KviOption_boolUseSSLCertificate));
 
114
        connect(b,SIGNAL(toggled(bool)),f,SLOT(setEnabled(bool)));
 
115
        KviPasswordSelector * p = new KviPasswordSelector(gbox,__tr2qs_ctx("Certificate password:","options"),
 
116
                &(KVI_OPTION_STRING(KviOption_stringSSLCertificatePass)),KVI_OPTION_BOOL(KviOption_boolUseSSLCertificate));
 
117
        connect(b,SIGNAL(toggled(bool)),p,SLOT(setEnabled(bool)));
 
118
 
 
119
        gbox = addGroupBox(0,1,0,1,Qt::Horizontal,__tr2qs_ctx("Private Key","options"));
 
120
        b = addBoolSelector(gbox,__tr2qs_ctx("Use SSL private key","options"),
 
121
                &(KVI_OPTION_BOOL(KviOption_boolUseSSLPrivateKey)),true);
 
122
        f = addFileSelector(gbox,__tr2qs_ctx("Private key location:","options"),
 
123
                &(KVI_OPTION_STRING(KviOption_stringSSLPrivateKeyPath)),KVI_OPTION_BOOL(KviOption_boolUseSSLPrivateKey));
 
124
        connect(b,SIGNAL(toggled(bool)),f,SLOT(setEnabled(bool)));
 
125
        p = addPasswordSelector(gbox,__tr2qs_ctx("Private key password:","options"),
 
126
                &(KVI_OPTION_STRING(KviOption_stringSSLPrivateKeyPass)),KVI_OPTION_BOOL(KviOption_boolUseSSLPrivateKey));
 
127
        connect(b,SIGNAL(toggled(bool)),p,SLOT(setEnabled(bool)));
 
128
 
 
129
        b = addBoolSelector(this,__tr2qs_ctx("Use the STARTTLS security protocol if available","options"),&(KVI_OPTION_BOOL(KviOption_boolUseStartTlsIfAvailable)),true);
 
130
        mergeTip(b,__tr2qs_ctx("<center>This option will cause KVIrc to try to reconnect to the server using an encrypted connection</center>","options"));
 
131
        addWidgetToLayout(b,0,2,0,2);
 
132
 
 
133
        addRowSpacer(0,3,0,3);
 
134
#else
 
135
        addLabel(0,0,0,0,__tr2qs_ctx("This executable has no SSL support.","options"));
 
136
#endif
 
137
}
 
138
 
 
139
OptionsWidget_connectionSsl::~OptionsWidget_connectionSsl()
 
140
{
 
141
}
 
142
 
 
143
 
 
144
OptionsWidget_connectionSocket::OptionsWidget_connectionSocket(QWidget * parent)
 
145
: KviOptionsWidget(parent)
 
146
{
 
147
        setObjectName("transport_options_widget");
 
148
        createLayout();
 
149
        KviUIntSelector * u;
 
150
 
 
151
        KviTalGroupBox * g = addGroupBox(0,0,0,0,Qt::Horizontal,__tr2qs_ctx("Timeout Values","options"),this);
 
152
        u = addUIntSelector(g,__tr2qs_ctx("Connect timeout:","options"),KviOption_uintIrcSocketTimeout,5,6000,60);
 
153
        u->setSuffix(__tr2qs_ctx(" sec","options"));
 
154
        u = addUIntSelector(g,__tr2qs_ctx("Outgoing data queue flush timeout:","options"),KviOption_uintSocketQueueFlushTimeout,100,2000,500);
 
155
        u->setSuffix(__tr2qs_ctx(" msec","options"));
 
156
        KviBoolSelector * b = addBoolSelector(0,1,0,1,__tr2qs_ctx("Limit outgoing traffic","options"),KviOption_boolLimitOutgoingTraffic);
 
157
        u = addUIntSelector(0,2,0,2,__tr2qs_ctx("Limit to 1 message every:","options"),
 
158
                        KviOption_uintOutgoingTrafficLimitUSeconds,10000,2000000,10000001,KVI_OPTION_BOOL(KviOption_boolLimitOutgoingTraffic));
 
159
        u->setSuffix(__tr2qs_ctx(" usec","options"));
 
160
        mergeTip(u,__tr2qs_ctx("<center>Minimum value: <b>10000 usec</b><br>Maximum value: <b>10000000 usec</b></center>","options"));
 
161
        connect(b,SIGNAL(toggled(bool)),u,SLOT(setEnabled(bool)));
 
162
 
 
163
        g = addGroupBox(0,3,0,3,Qt::Horizontal,__tr2qs_ctx("Network Interfaces","options"));
 
164
 
 
165
        b = addBoolSelector(g,__tr2qs_ctx("Bind IPv4 connections to:","options"),KviOption_boolBindIrcIPv4ConnectionsToSpecifiedAddress);
 
166
        KviStringSelector * s = addStringSelector(g,"",KviOption_stringIPv4ConnectionBindAddress,KVI_OPTION_BOOL(KviOption_boolBindIrcIPv4ConnectionsToSpecifiedAddress));
 
167
        connect(b,SIGNAL(toggled(bool)),s,SLOT(setEnabled(bool)));
 
168
#ifdef COMPILE_IPV6_SUPPORT
 
169
        b = addBoolSelector(g,__tr2qs_ctx("Bind IPv6 connections to:","options"),KviOption_boolBindIrcIPv6ConnectionsToSpecifiedAddress);
 
170
        s = addStringSelector(g,"",KviOption_stringIPv6ConnectionBindAddress,KVI_OPTION_BOOL(KviOption_boolBindIrcIPv6ConnectionsToSpecifiedAddress));
 
171
        connect(b,SIGNAL(toggled(bool)),s,SLOT(setEnabled(bool)));
 
172
#endif //!COMPILE_IPV6_SUPPORT
 
173
 
 
174
        b = addBoolSelector(0,4,0,4,__tr2qs_ctx("Pick Random IP Address for Round-Robin Servers","options"),KviOption_boolPickRandomIpAddressForRoundRobinServers);
 
175
        mergeTip(b,__tr2qs_ctx("<center>This option will cause the KVIrc networking stack to pick up " \
 
176
                "a random entry when multiple IP address are retrieved for a server " \
 
177
                "dns lookup. This is harmless and can fix some problems with caching " \
 
178
                "dns servers that do not properly rotate the records as the authoritative " \
 
179
                "ones would do. On the other hand, you might want to disable it if " \
 
180
                "you want to rely on the dns server to provide the best choice.</center>","options"));
 
181
 
 
182
        addRowSpacer(0,5,0,5);
 
183
}
 
184
 
 
185
OptionsWidget_connectionSocket::~OptionsWidget_connectionSocket()
 
186
{
 
187
}
 
188
 
 
189
 
 
190
OptionsWidget_identService::OptionsWidget_identService(QWidget * parent)
 
191
: KviOptionsWidget(parent)
 
192
{
 
193
        setObjectName("ident_options_widget");
 
194
        createLayout();
 
195
 
 
196
        m_pEnableIdent = addBoolSelector(0,0,0,0,__tr2qs_ctx("Enable ident service (bad practice on UNIX!)","options"),KviOption_boolUseIdentService);
 
197
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),this,SLOT(enableIpv4InIpv6(bool)));
 
198
 
 
199
        KviTalGroupBox * gbox = addGroupBox(0,1,0,1,Qt::Horizontal,__tr2qs_ctx("Output verbosity","options"),KVI_OPTION_BOOL(KviOption_boolUseIdentService));
 
200
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),gbox,SLOT(setEnabled(bool)));
 
201
 
 
202
        addLabel(gbox,__tr2qs_ctx("Output identd messages to:","options"));
 
203
 
 
204
        m_pActiveRadio = new QRadioButton(__tr2qs_ctx("Active window","options"),gbox);
 
205
        m_pConsoleRadio = new QRadioButton(__tr2qs_ctx("Console","options"),gbox);
 
206
        m_pQuietRadio = new QRadioButton(__tr2qs_ctx("Do not show any identd messages","options"),gbox);
 
207
 
 
208
        switch(KVI_OPTION_UINT(KviOption_uintIdentdOutputMode))
 
209
        {
 
210
                case KviIdentdOutputMode::Quiet :
 
211
                        m_pQuietRadio->setChecked(true);
 
212
                        break;
 
213
                case KviIdentdOutputMode::ToConsole :
 
214
                        m_pConsoleRadio->setChecked(true);
 
215
                        break;
 
216
                case KviIdentdOutputMode::ToActiveWindow :
 
217
                        m_pActiveRadio->setChecked(true);
 
218
                        break;
 
219
        }
 
220
 
 
221
        gbox = addGroupBox(0,2,0,2,Qt::Horizontal,__tr2qs_ctx("Configuration","options"),KVI_OPTION_BOOL(KviOption_boolUseIdentService));
 
222
 
 
223
        KviBoolSelector *b = addBoolSelector(gbox,__tr2qs_ctx("Enable ident service only while connecting to server","options"),KviOption_boolUseIdentServiceOnlyOnConnect);
 
224
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),b,SLOT(setEnabled(bool)));
 
225
 
 
226
        KviStringSelector * s = addStringSelector(gbox,__tr2qs_ctx("Ident username:","options"),
 
227
                KviOption_stringIdentdUser,KVI_OPTION_BOOL(KviOption_boolUseIdentService));
 
228
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),s,SLOT(setEnabled(bool)));
 
229
 
 
230
        KviUIntSelector * u = addUIntSelector(gbox,__tr2qs_ctx("Service port:","options"),
 
231
                KviOption_uintIdentdPort,0,65535,113,KVI_OPTION_BOOL(KviOption_boolUseIdentService));
 
232
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),u,SLOT(setEnabled(bool)));
 
233
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),gbox,SLOT(setEnabled(bool)));
 
234
 
 
235
        gbox = addGroupBox(0,3,0,3,Qt::Horizontal,__tr2qs_ctx("IPv6 Settings","options"),KVI_OPTION_BOOL(KviOption_boolUseIdentService));
 
236
        m_pEnableIpv6 = addBoolSelector(gbox,__tr2qs_ctx("Enable service for IPv6","options"),
 
237
                KviOption_boolIdentdEnableIPv6,
 
238
                KVI_OPTION_BOOL(KviOption_boolUseIdentService));
 
239
#ifdef COMPILE_IPV6_SUPPORT
 
240
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),m_pEnableIpv6,SLOT(setEnabled(bool)));
 
241
        connect(m_pEnableIpv6,SIGNAL(toggled(bool)),this,SLOT(enableIpv4InIpv6(bool)));
 
242
#else
 
243
        m_pEnableIpv6->setEnabled(false);
 
244
#endif
 
245
        m_pIpv4InIpv6 = addBoolSelector(gbox,__tr2qs_ctx("IP stack treats IPv4 as part of IPv6 namespace","options"),
 
246
                KviOption_boolIdentdIPv6ContainsIPv4,
 
247
                KVI_OPTION_BOOL(KviOption_boolUseIdentService) && KVI_OPTION_BOOL(KviOption_boolIdentdEnableIPv6));
 
248
        connect(m_pEnableIdent,SIGNAL(toggled(bool)),gbox,SLOT(setEnabled(bool)));
 
249
 
 
250
        addLabel(0,4,0,4,
 
251
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
 
252
                        __tr2qs_ctx("<p><b>Warning:</b><br>" \
 
253
                        "This is a <b>non RFC 1413 compliant</b> ident daemon that implements " \
 
254
                        "only a limited subset of the Identification Protocol specifications. If it is possible, install a " \
 
255
                        "real ident daemon.</p>","options")
 
256
#else
 
257
                        __tr2qs_ctx("<p><b>Warning:</b><br>" \
 
258
                        "This is a <b>non RFC 1413 compliant</b> ident daemon that implements " \
 
259
                        "only a limited subset of the Identification Protocol specifications.<br>" \
 
260
                        "On UNIX, you may also need root privileges to bind to the auth port (113).<br>" \
 
261
                        "It is <b>highly recommended</b> that a <b>real</b> system-wide ident daemon be used instead, "\
 
262
                        "or none at all if ident is not required.</p>","options")
 
263
#endif
 
264
        );
 
265
 
 
266
        addRowSpacer(0,5,0,5);
 
267
}
 
268
 
 
269
OptionsWidget_identService::~OptionsWidget_identService()
 
270
{
 
271
}
 
272
 
 
273
void OptionsWidget_identService::commit()
 
274
{
 
275
        KviOptionsWidget::commit();
 
276
        if(m_pConsoleRadio->isChecked())
 
277
                KVI_OPTION_UINT(KviOption_uintIdentdOutputMode)=KviIdentdOutputMode::ToConsole;
 
278
        if(m_pActiveRadio->isChecked())
 
279
                KVI_OPTION_UINT(KviOption_uintIdentdOutputMode)=KviIdentdOutputMode::ToActiveWindow;
 
280
        if(m_pQuietRadio->isChecked())
 
281
                KVI_OPTION_UINT(KviOption_uintIdentdOutputMode)=KviIdentdOutputMode::Quiet;
 
282
}
 
283
 
 
284
void OptionsWidget_identService::enableIpv4InIpv6(bool)
 
285
{
 
286
#ifdef COMPILE_IPV6_SUPPORT
 
287
        m_pIpv4InIpv6->setEnabled(m_pEnableIdent->isChecked() && m_pEnableIpv6->isChecked());
 
288
#endif
 
289
}
 
290
 
 
291
 
 
292
OptionsWidget_connectionAdvanced::OptionsWidget_connectionAdvanced(QWidget * parent)
 
293
: KviOptionsWidget(parent)
 
294
{
 
295
        setObjectName("connection_advanced_options_widget");
 
296
}
 
297
 
 
298
OptionsWidget_connectionAdvanced::~OptionsWidget_connectionAdvanced()
 
299
{
 
300
}
 
301
 
 
302
#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
 
303
#include "m_OptionsWidget_connection.moc"
 
304
#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES