1<%@ page contentType="text/html; charset=UTF-8" %>
2<%--
3  -
4  - Copyright (C) 2004-2008 Jive Software. All rights reserved.
5  -
6  - Licensed under the Apache License, Version 2.0 (the "License");
7  - you may not use this file except in compliance with the License.
8  - You may obtain a copy of the License at
9  -
10  -     http://www.apache.org/licenses/LICENSE-2.0
11  -
12  - Unless required by applicable law or agreed to in writing, software
13  - distributed under the License is distributed on an "AS IS" BASIS,
14  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  - See the License for the specific language governing permissions and
16  - limitations under the License.
17--%>
18
19<%@ page import="org.jivesoftware.openfire.SessionManager,
20                 org.jivesoftware.openfire.SessionResultFilter,
21                 org.jivesoftware.openfire.session.ClientSession,
22                 org.jivesoftware.util.JiveGlobals,
23                 org.jivesoftware.util.ParamUtils,
24                 org.jivesoftware.util.CookieUtils,
25                 org.jivesoftware.util.StringUtils"
26    errorPage="error.jsp"
27%>
28<%@ page import="java.util.Date" %>
29<%@ page import="org.jivesoftware.util.ListPager" %>
30<%@ page import="java.util.function.Predicate" %>
31<%@ page import="java.net.UnknownHostException" %>
32<%@ page import="java.util.Collection" %>
33<%@ page import="java.util.List" %>
34<%@ page import="java.util.ArrayList" %>
35<%@ page import="org.jivesoftware.openfire.cluster.ClusterManager" %>
36<%@ page import="org.slf4j.LoggerFactory" %>
37
38<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
39<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
40<%!
41    private static final String NONE = LocaleUtils.getLocalizedString("global.none");
42
43    private static final int[] REFRESHES = {0, 10, 30, 60, 90};
44    private static final String[] REFRESHES_LABELS = {NONE,"10","30","60","90"};
45%>
46<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager"  />
47<% webManager.init(request, response, session, application, out ); %>
48
49<%  // Get parameters
50    int refresh = ParamUtils.getIntParameter(request,"refresh",webManager.getRefreshValue("session-summary", 0));
51    pageContext.setAttribute("refresh", refresh);
52    boolean close = ParamUtils.getBooleanParameter(request,"close");
53    int order = ParamUtils.getIntParameter(request, "order",
54            webManager.getPageProperty("session-summary", "console.order", SessionResultFilter.ASCENDING));
55    String jid = ParamUtils.getParameter(request,"jid");
56
57    if (request.getParameter("refresh") != null) {
58        webManager.setRefreshValue("session-summary", refresh);
59    }
60
61    if (request.getParameter("order") != null) {
62        webManager.setPageProperty("session-summary", "console.order", order);
63    }
64
65    // Get the user manager
66    SessionManager sessionManager = webManager.getSessionManager();
67
68    Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
69    String csrfParam = ParamUtils.getParameter(request, "csrf");
70
71    if (close) {
72        if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
73            close = false;
74        }
75    }
76    csrfParam = StringUtils.randomString(15);
77    CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
78    pageContext.setAttribute("csrf", csrfParam);
79    // Close a connection if requested
80    if (close) {
81        JID address = new JID(jid);
82        try {
83            Session sess = sessionManager.getSession(address);
84            sess.close();
85            // Log the event
86            webManager.logEvent("closed session for address "+address, null);
87            // wait one second
88            Thread.sleep(1000L);
89        }
90        catch (Exception e) {
91            // Session might have disappeared on its own
92            LoggerFactory.getLogger("session-summary.jsp").warn("Unable to manually close session for address: {}", address, e);
93        }
94        // Redirect back to this page
95        response.sendRedirect("session-summary.jsp?close=success");
96        return;
97    }
98
99    SessionResultFilter sessionResultFilter = SessionResultFilter.createDefaultSessionFilter();
100    sessionResultFilter.setSortOrder(order);
101    // Filter out the dodgy looking sessions
102    List<ClientSession> sessions = new ArrayList<>(sessionManager.getSessions( sessionResultFilter));
103
104    // By default, display all nodes
105    Predicate<ClientSession> filter = clientSession -> true;
106    final String searchName = ParamUtils.getStringParameter(request, "searchName", "");
107    if(!searchName.trim().isEmpty()) {
108        final String searchCriteria = searchName.trim();
109        filter = filter.and(clientSession -> StringUtils.containsIgnoringCase(clientSession.getAddress().getNode(), searchCriteria));
110    }
111    final String searchResource = ParamUtils.getStringParameter(request, "searchResource", "");
112    if(!searchResource.trim().isEmpty()) {
113        final String searchCriteria = searchResource.trim();
114        filter = filter.and(clientSession -> StringUtils.containsIgnoringCase(clientSession.getAddress().getResource(), searchCriteria));
115    }
116    final String searchVersion = ParamUtils.getStringParameter(request, "searchVersion", "");
117        if(!searchVersion.trim().isEmpty()) {
118            final String searchCriteria = searchVersion.trim();
119            // TODO: Fix this filter
120            filter = filter.and(clientSession -> StringUtils.containsIgnoringCase(clientSession.getAddress().getResource(), searchCriteria));
121        }
122    final String searchNode = ParamUtils.getStringParameter(request, "searchNode", "");
123    if(searchNode.equals("local")) {
124        filter = filter.and(LocalClientSession.class::isInstance);
125    } else if (searchNode.equals("remote")) {
126        filter = filter.and(clientSession -> !LocalClientSession.class.isInstance(clientSession));
127    }
128    final String searchStatus = ParamUtils.getStringParameter(request, "searchStatus", "");
129    if(!searchStatus.isEmpty()) {
130        filter = filter.and(clientSession -> {
131            if (searchStatus.equals("detached")) {
132                return clientSession instanceof LocalSession && ((LocalSession) clientSession).isDetached();
133            }
134            switch (clientSession.getStatus()) {
135                case Session.STATUS_CLOSED:
136                    return "closed".equals(searchStatus);
137                case Session.STATUS_CONNECTED:
138                    return "connected".equals(searchStatus);
139                case Session.STATUS_AUTHENTICATED:
140                    return "authenticated".equals(searchStatus);
141                default:
142                    return "unknown".equals(searchStatus);
143            }
144        });
145    }
146    final String searchPresence = ParamUtils.getStringParameter(request, "searchPresence", "");
147    if(!searchPresence.isEmpty()) {
148        filter = filter.and(clientSession -> {
149            final Presence presence = clientSession.getPresence();
150            if (!presence.isAvailable()) {
151                return "offline".equals(searchPresence);
152            }
153            final Presence.Show show = presence.getShow();
154            if (show == null) {
155                return "online".equals(searchPresence);
156            }
157            switch (show) {
158                case away:
159                    return "away".equals(searchPresence);
160                case chat:
161                    return "chat".equals(searchPresence);
162                case dnd:
163                    return "dnd".equals(searchPresence);
164                case xa:
165                    return "xa".equals(searchPresence);
166                default:
167                    return "unknown".equals(searchPresence);
168            }
169        });
170    }
171    final String searchPriority = ParamUtils.getStringParameter(request, "searchPriority", "");
172    if (!searchPriority.trim().isEmpty()) {
173        int intValue;
174        try {
175            intValue = Integer.parseInt(searchPriority.trim());
176        } catch (final NumberFormatException e) {
177            // If we can't parse it, use a default which no session can actually have
178            intValue = Integer.MIN_VALUE;
179        }
180        final int searchCriteria = intValue;
181        filter = filter.and(clientSession -> clientSession.getPresence().getPriority() == searchCriteria);
182    }
183    final String searchHostAddress = ParamUtils.getStringParameter(request, "searchHostAddress", "");
184    if(!searchHostAddress.trim().isEmpty()) {
185        final String searchCriteria = searchHostAddress.trim();
186        filter = filter.and(clientSession -> {
187            try {
188                return StringUtils.containsIgnoringCase(clientSession.getHostAddress(), searchCriteria);
189            } catch (final UnknownHostException e) {
190                return false;
191            }
192        });
193    }
194
195    final ListPager<ClientSession> listPager = new ListPager<>(request, response, sessions, filter,
196        "refresh", "searchName", "searchResource", "searchVersion", "searchNode", "searchStatus", "searchPresence", "searchPriority", "searchHostAddress");
197    pageContext.setAttribute("listPager", listPager);
198    pageContext.setAttribute("searchName", searchName);
199    pageContext.setAttribute("searchResource", searchResource);
200    pageContext.setAttribute("searchVersion", searchVersion);
201    pageContext.setAttribute("searchNode", searchNode);
202    pageContext.setAttribute("searchStatus", searchStatus);
203    pageContext.setAttribute("searchPresence", searchPresence);
204    pageContext.setAttribute("searchPriority", searchPriority);
205    pageContext.setAttribute("searchHostAddress", searchHostAddress);
206    pageContext.setAttribute("clusteringEnabled", ClusterManager.isClusteringStarted() || ClusterManager.isClusteringStarting() );
207%>
208<html>
209    <head>
210        <title><fmt:message key="session.summary.title"/></title>
211        <meta name="pageID" content="session-summary"/>
212        <meta name="helpPage" content="view_active_client_sessions.html"/>
213        <c:if test="${refresh > 0}">
214            <meta http-equiv="refresh" content="${refresh}">
215        </c:if>
216    </head>
217    <body>
218
219<%  if ("success".equals(request.getParameter("close"))) { %>
220
221    <p class="jive-success-text">
222    <fmt:message key="session.summary.close" />
223    </p>
224
225<%  } %>
226
227<table cellpadding="0" cellspacing="0" border="0" width="100%">
228<tbody>
229    <tr valign="top">
230        <td width="99%">
231            <fmt:message key="session.summary.active" />: <b>${listPager.totalItemCount}</b>
232            <c:if test="${listPager.filtered}">
233                <fmt:message key="session.summary.filtered_session_count" />: <c:out value="${listPager.filteredItemCount}"/>
234            </c:if>
235        <c:if test="${listPager.totalPages > 1}">
236                -- <fmt:message key="global.showing" /> <c:out value="${listPager.firstItemNumberOnPage}"/>-<c:out value="${listPager.lastItemNumberOnPage}"/>
237                <p><fmt:message key="global.pages" />: [ ${listPager.pageLinks} ]
238            </c:if>
239            -- <fmt:message key="session.summary.sessions_per_page" />:
240            ${listPager.pageSizeSelection}
241        </td>
242        <td width="1%" nowrap>
243            <label for="refresh"><fmt:message key="global.refresh" />:</label>
244            <select size="1" id="refresh" name="refresh" onchange="submitForm();">
245            <%  for (int j=0; j<REFRESHES.length; j++) {
246                    String selected = REFRESHES[j] == refresh ? " selected" : "";
247            %>
248                <option value="<%= REFRESHES[j] %>"<%= selected %>><%= REFRESHES_LABELS[j] %>
249
250            <%  } %>
251            </select>
252            (<fmt:message key="global.seconds" />)
253
254        </td>
255    </tr>
256</tbody>
257</table>
258<br>
259
260
261<div class="jive-table">
262<table cellpadding="0" cellspacing="0" border="0" width="100%">
263<thead>
264    <tr>
265        <th>&nbsp;</th>
266        <th nowrap>
267        <%
268            if (sessionResultFilter.getSortField() == SessionResultFilter.SORT_USER) {
269                if (sessionResultFilter.getSortOrder() == SessionResultFilter.DESCENDING) {
270        %>
271        <table border="0"><tr valign="middle"><th>
272        <a href="session-summary.jsp?order=<%=SessionResultFilter.ASCENDING %>">
273        <fmt:message key="session.details.name" /></a>
274        </th><th>
275        <a href="session-summary.jsp?order=<%=SessionResultFilter.ASCENDING %>">
276        <img src="images/sort_descending.gif" border="0" width="16" height="16" alt=""></a>
277        </th></tr></table>
278        <%
279                }
280                else {
281        %>
282        <table border="0"><tr valign="middle"><th>
283        <a href="session-summary.jsp?order=<%=SessionResultFilter.DESCENDING %>">
284        <fmt:message key="session.details.name" /></a>
285        </th><th>
286        <a href="session-summary.jsp?order=<%=SessionResultFilter.DESCENDING %>">
287        <img src="images/sort_ascending.gif" width="16" height="16" border="0" alt=""></a>
288        </th></tr></table>
289        <%
290                }
291            }
292            else {
293        %>
294            <fmt:message key="session.details.name" />
295        <%
296            }
297        %>
298        </th>
299        <th nowrap><fmt:message key="session.details.resource" /></th>
300        <th nowrap><fmt:message key="session.details.version" /></th>
301        <c:if test="${clusteringEnabled}">
302        <th nowrap><fmt:message key="session.details.node" /></th>
303        </c:if>
304        <th nowrap colspan="2"><fmt:message key="session.details.status" /></th>
305        <th nowrap colspan="2"><fmt:message key="session.details.presence" /></th>
306        <th nowrap><fmt:message key="session.details.priority" /></th>
307        <th nowrap><fmt:message key="session.details.clientip" /></th>
308        <th nowrap><fmt:message key="session.details.close_connect" /></th>
309    </tr>
310    <tr>
311        <td nowrap></td>
312        <td nowrap>
313            <input type="search"
314                   id="searchName"
315                   size="20"
316                   value="<c:out value="${searchName}"/>"/>
317            <img src="images/search-16x16.png"
318                 width="16" height="16"
319                 alt="search" title="search"
320                 style="vertical-align: middle;"
321                 onclick="submitForm();"
322            >
323        </td>
324        <td nowrap>
325            <input type="search"
326                   id="searchResource"
327                   size="20"
328                   value="<c:out value="${searchResource}"/>"/>
329            <img src="images/search-16x16.png"
330                 width="16" height="16"
331                 alt="search" title="search"
332                 style="vertical-align: middle;"
333                 onclick="submitForm();"
334            >
335        </td>
336        <td nowrap>
337            <input type="search"
338                   id="searchVersion"
339                   size="20"
340                   value="<c:out value="${searchVersion}"/>"/>
341            <img src="images/search-16x16.png"
342                 width="16" height="16"
343                 alt="search" title="search"
344                 style="vertical-align: middle;"
345                 onclick="submitForm();"
346            >
347        </td>
348        <c:if test="${clusteringEnabled}">
349        <td nowrap>
350            <select id="searchNode" onchange="submitForm();">
351                <option <c:if test='${searchNode eq ""}'>selected</c:if> value=""></option>
352                <option <c:if test='${searchNode eq "local"}'>selected </c:if>value="local"><fmt:message key="session.details.local"/></option>
353                <option <c:if test='${searchNode eq "remote"}'>selected </c:if>value="remote"><fmt:message key="session.details.remote"/></option>
354            </select>
355        </td>
356        </c:if>
357        <td nowrap colspan="2">
358            <select id="searchStatus" onchange="submitForm();">
359                <option <c:if test='${searchStatus eq ""}'>selected</c:if> value=""></option>
360                <option <c:if test='${searchStatus eq "closed"}'>selected</c:if> value="closed"><fmt:message key="session.details.close"/></option>
361                <option <c:if test='${searchStatus eq "connected"}'>selected</c:if> value="connected"><fmt:message key="session.details.connect"/></option>
362                <option <c:if test='${searchStatus eq "authenticated"}'>selected</c:if> value="authenticated"><fmt:message key="session.details.authenticated"/></option>
363                <option <c:if test='${searchStatus eq "detached"}'>selected</c:if> value="detached"><fmt:message key="session.details.local"/> & <fmt:message key="session.details.sm-detached"/></option>
364                <option <c:if test='${searchStatus eq "unknown"}'>selected</c:if> value="unknown"><fmt:message key="session.details.unknown"/></option>
365            </select>
366        </td>
367        <td nowrap colspan="2">
368            <select id="searchPresence" onchange="submitForm();">
369                <option <c:if test='${searchPresence eq ""}'>selected</c:if> value=""></option>
370                <option <c:if test='${searchPresence eq "online"}'>selected</c:if> value="online"><fmt:message key="session.details.online"/></option>
371                <option <c:if test='${searchPresence eq "away"}'>selected</c:if> value="away"><fmt:message key="session.details.away"/></option>
372                <option <c:if test='${searchPresence eq "xa"}'>selected</c:if> value="xa"><fmt:message key="session.details.extended"/></option>
373                <option <c:if test='${searchPresence eq "offline"}'>selected</c:if> value="offline"><fmt:message key="user.properties.offline"/></option>
374                <option <c:if test='${searchPresence eq "chat"}'>selected</c:if> value="chat"><fmt:message key="session.details.chat_available"/></option>
375                <option <c:if test='${searchPresence eq "dnd"}'>selected</c:if> value="dnd"><fmt:message key="session.details.not_disturb"/></option>
376                <option <c:if test='${searchPresence eq "unknown"}'>selected</c:if> value="unknown"><fmt:message key="session.details.unknown"/></option>
377            </select>
378        </td>
379        <td nowrap>
380            <input type="search"
381                   id="searchPriority"
382                   size="5"
383                   min="-128"
384                   max="127"
385                   value="<c:out value="${searchPriority}"/>"/>
386            <img src="images/search-16x16.png"
387                 width="16" height="16"
388                 alt="search" title="search"
389                 style="vertical-align: middle;"
390                 onclick="submitForm();"
391            >
392        </td>
393        <td nowrap>
394            <input type="search"
395                   id="searchHostAddress"
396                   size="20"
397                   value="<c:out value="${searchHostAddress}"/>"/>
398            <img src="images/search-16x16.png"
399                 width="16" height="16"
400                 alt="search" title="search"
401                 style="vertical-align: middle;"
402                 onclick="submitForm();"
403            >
404        </td>
405        <td nowrap></td>
406    </tr>
407</thead>
408<tbody>
409    <%
410        if (sessions.isEmpty()) {
411    %>
412        <tr>
413            <td colspan="11">
414
415                <fmt:message key="session.summary.not_session" />
416
417            </td>
418        </tr>
419
420    <%  } %>
421
422    <%
423        // needed in session-row.jspf
424        int count = listPager.getFirstItemNumberOnPage();
425        final boolean current = false;
426        final String linkURL = "session-details.jsp";
427        for (final ClientSession sess : listPager.getItemsOnCurrentPage()) {
428    %>
429        <%@ include file="session-row.jspf" %>
430    <%  count++;
431        } %>
432
433</tbody>
434</table>
435</div>
436
437<c:if test="${listPager.totalPages > 1}">
438<p><fmt:message key="global.pages" />: [ ${listPager.pageLinks} ]</p>
439</c:if>
440
441<br>
442<p>
443<fmt:message key="session.summary.last_update" />: <%= JiveGlobals.formatDateTime(new Date()) %>
444</p>
445
446${listPager.jumpToPageForm}
447
448<script type="text/javascript">
449    ${listPager.pageFunctions}
450</script>
451    </body>
452</html>
453