aboutsummaryrefslogtreecommitdiff
path: root/juick-api/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'juick-api/src/main')
-rw-r--r--juick-api/src/main/java/com/juick/api/Main.java458
-rw-r--r--juick-api/src/main/java/com/juick/api/Messages.java188
-rw-r--r--juick-api/src/main/java/com/juick/api/Others.java53
-rw-r--r--juick-api/src/main/java/com/juick/api/PM.java109
-rw-r--r--juick-api/src/main/java/com/juick/api/TelegramBotHook.java243
-rw-r--r--juick-api/src/main/java/com/juick/api/Users.java126
-rw-r--r--juick-api/src/main/java/com/juick/api/Utils.java231
-rw-r--r--juick-api/src/main/webapp/WEB-INF/juick.conf.example6
-rw-r--r--juick-api/src/main/webapp/WEB-INF/web.xml16
9 files changed, 1430 insertions, 0 deletions
diff --git a/juick-api/src/main/java/com/juick/api/Main.java b/juick-api/src/main/java/com/juick/api/Main.java
new file mode 100644
index 000000000..afd7c11c2
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/Main.java
@@ -0,0 +1,458 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2013, Ugnich Anton
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.juick.api;
+
+import com.juick.Tag;
+import com.juick.json.MessageSerializer;
+import com.juick.server.MessagesQueries;
+import com.juick.server.SubscriptionsQueries;
+import com.juick.server.TagQueries;
+import com.juick.server.UserQueries;
+import com.juick.xmpp.JID;
+import com.juick.xmpp.Message;
+import com.juick.xmpp.Stream;
+import com.juick.xmpp.StreamComponent;
+import com.juick.xmpp.extensions.JuickMessage;
+import com.juick.xmpp.extensions.Nickname;
+import com.juick.xmpp.extensions.XOOB;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.MultipartConfig;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.LogManager;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@WebServlet(name = "Main", urlPatterns = {"/"})
+@MultipartConfig
+public class Main extends HttpServlet implements Stream.StreamListener {
+
+ JdbcTemplate jdbc;
+ Stream xmpp;
+ Messages messages;
+ Users users;
+ PM pm;
+ Others others;
+ TelegramBotHook tgb;
+
+ @Override
+ public void init() throws ServletException {
+ super.init();
+ try {
+ LogManager.getLogManager().readConfiguration(getServletContext().getResourceAsStream("/WEB-INF/logging.properties"));
+ Properties conf = new Properties();
+ conf.load(getServletContext().getResourceAsStream("/WEB-INF/juick.conf"));
+ DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(conf.getProperty("datasource_driver", "com.mysql.jdbc.Driver"));
+ dataSource.setUrl(conf.getProperty("datasource_url"));
+ jdbc = new JdbcTemplate(dataSource);
+ messages = new Messages(jdbc);
+ users = new Users(jdbc);
+ pm = new PM(jdbc);
+ others = new Others(jdbc);
+ tgb = new TelegramBotHook(jdbc, conf.getProperty("telegram_token", ""));
+ setupXmppComponent(conf.getProperty("xmpp_host", "localhost"), Integer.parseInt(conf.getProperty("xmpp_port", "5347")),
+ conf.getProperty("xmpp_jid", "api.localhost"), conf.getProperty("xmpp_password"));
+
+ } catch (IOException e) {
+ log("API initialization error", e);
+ }
+ }
+
+ public void setupXmppComponent(final String host, final int port, final String jid, final String password) {
+ ExecutorService executorService = Executors.newSingleThreadExecutor();
+ executorService.submit(() -> {
+ try {
+ Socket socket = new Socket(host, port);
+ xmpp = new StreamComponent(new JID(jid), socket.getInputStream(), socket.getOutputStream(), password);
+ xmpp.addListener(Main.this);
+ xmpp.startParsing();
+ } catch (IOException e) {
+ log("XMPP exception", e);
+ }
+ });
+ }
+
+ @Override
+ public void onStreamFail(Exception e) {
+ log("XMPP failed", e);
+ }
+
+ @Override
+ public void onStreamReady() {
+ log("XMPP STREAM READY");
+ }
+
+ /**
+ * Handles the HTTP <code>GET</code> method.
+ * @param request servlet request
+ * @param response servlet response
+ * @throws ServletException if a servlet-specific error occurs
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (request.getCharacterEncoding() == null) {
+ request.setCharacterEncoding("UTF-8");
+ }
+
+ String uri = request.getRequestURI();
+
+ int vuid = Utils.getHttpAuthUID(jdbc, request);
+ if (vuid == 0) {
+ vuid = Utils.getVisitorQueryStringUID(jdbc, request);
+ }
+
+ if (uri.equals("/home")) {
+ if (vuid > 0) {
+ messages.doGetHome(request, response, vuid);
+ } else {
+ response.sendError(401);
+ }
+ } else if (uri.equals("/messages")) {
+ messages.doGet(request, response, vuid);
+ } else if (uri.equals("/thread")) {
+ messages.doThreadGet(request, response, vuid);
+ } else if (uri.equals("/users")) {
+ users.doGetUsers(request, response, vuid);
+ } else if (uri.equals("/users/read")) {
+ users.doGetUserRead(request, response, vuid);
+ } else if (uri.equals("/users/readers")) {
+ users.doGetUserReaders(request, response, vuid);
+ } else if (uri.equals("/pm")) {
+ if (vuid > 0) {
+ pm.doGetPM(request, response, vuid);
+ } else {
+ response.sendError(401);
+ }
+ } else if (uri.equals("/groups_pms")) {
+ if (vuid > 0) {
+ others.doGetGroupsPMs(request, response, vuid);
+ } else {
+ response.sendError(401);
+ }
+ } else if (uri.equals("/messages/recommended")) {
+ if (vuid > 0) {
+ messages.doGetRecommended(request, response, vuid);
+ } else {
+ response.sendError(401);
+ }
+ } else if (uri.equals("/messages/set_popular") && vuid == 3694) {
+ messages.doSetPopular(request, response, xmpp);
+ } else if (uri.equals("/messages/set_privacy") && vuid > 0) {
+ messages.doSetPrivacy(request, response, xmpp, vuid);
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ /**
+ * Handles the HTTP <code>POST</code> method.
+ * @param request servlet request
+ * @param response servlet response
+ * @throws ServletException if a servlet-specific error occurs
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (request.getCharacterEncoding() == null) {
+ request.setCharacterEncoding("UTF-8");
+ }
+ String uri = request.getRequestURI();
+ if (uri.equals("/tlgmbtwbhk")) {
+ tgb.doPost(request);
+ return;
+ }
+
+ int vuid = Utils.getHttpAuthUID(jdbc, request);
+ if (vuid == 0) {
+ vuid = Utils.getVisitorQueryStringUID(jdbc, request);
+ }
+ if (vuid == 0) {
+ response.sendError(401);
+ return;
+ }
+ switch (uri) {
+ case "/post":
+ int mid = Utils.parseInt(request.getParameter("mid"), 0);
+ if (mid == 0) {
+ doPostMessage(jdbc, request, response, xmpp, vuid);
+ } else {
+ doPostComment(jdbc, request, response, xmpp, vuid);
+ }
+ break;
+ case "/pm":
+ pm.doPostPM(request, response, xmpp, vuid);
+ break;
+ default:
+ response.sendError(405);
+ break;
+ }
+ }
+
+ public void doPostMessage(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response, Stream xmpp, int vuid)
+ throws ServletException, IOException {
+ String body = request.getParameter("body");
+ if (body == null || body.length() < 1 || body.length() > 4096) {
+ response.sendError(400);
+ return;
+ }
+ body = body.replace("\r", "");
+
+ String tagsStr = request.getParameter("tags");
+ List<Tag> tags = new ArrayList<>();
+ String tagsArr[] = new String[1];
+ if (tagsStr != null && !tagsStr.isEmpty()) {
+ tagsArr = tagsStr.split("[ \\,]");
+ for (int i = 0; i < tagsArr.length; i++) {
+ if (tagsArr[i].startsWith("*")) {
+ tagsArr[i] = tagsArr[i].substring(1);
+ }
+ if (tagsArr[i].length() > 64) {
+ tagsArr[i] = tagsArr[i].substring(0, 64);
+ }
+ }
+ tags = TagQueries.getTags(sql, tagsArr, true);
+ while (tags.size() > 5) {
+ tags.remove(5);
+ }
+ }
+
+ String attachmentFName = null;
+ try {
+ attachmentFName = Utils.receiveMultiPartFile(request, "attach");
+ } catch (Exception e) {
+ System.out.println("MULTIPART ERROR: " + e.toString());
+ response.sendError(400);
+ return;
+ }
+
+ String paramImg = request.getParameter("img");
+ if (attachmentFName == null && paramImg != null && paramImg.length() > 10 ) {
+ try {
+ URL imgUrl = new URL(paramImg);
+ attachmentFName = Utils.downloadImage(imgUrl);
+ } catch (Exception e) {
+ System.out.println("DOWNLOAD ERROR: " + e.toString());
+ response.sendError(500);
+ return;
+ }
+ }
+
+ String attachmentType = attachmentFName != null ? attachmentFName.substring(attachmentFName.length() - 3) : null;
+ int mid = MessagesQueries.createMessage(sql, vuid, body, attachmentType, tags);
+ SubscriptionsQueries.subscribeMessage(sql, mid, vuid);
+ JuickMessage jmsg = new JuickMessage(MessagesQueries.getMessage(sql, mid));
+ if (xmpp != null) {
+ Message xmsg = new Message();
+ xmsg.from = new JID("juick", "juick.com", null);
+ xmsg.type = Message.Type.chat;
+ xmsg.thread = "juick-" + mid;
+
+ xmsg.addChild(jmsg);
+
+ Nickname nick = new Nickname();
+ nick.Nickname = "@" + jmsg.getUser().getUName();
+ xmsg.addChild(nick);
+
+ if (attachmentFName != null) {
+ String fname = mid + "." + attachmentType;
+ String attachmentURL = "http://i.juick.com/photos-1024/" + fname;
+
+ Runtime.getRuntime().exec("/var/www/juick.com/cgi/p-convert.sh /var/www/juick.com/i/tmp/" + attachmentFName + " " + fname);
+
+ body = attachmentURL + "\n" + body;
+ XOOB xoob = new XOOB();
+ xoob.URL = attachmentURL;
+ xmsg.addChild(xoob);
+ }
+
+ String tagsStr2 = "";
+ for (String tag : tagsArr) {
+ tagsStr2 += " *" + tag;
+ }
+ xmsg.body = "@" + jmsg.getUser().getUName() + ":" + tagsStr2 + "\n" + body + "\n\n#" + mid + " http://juick.com/" + mid;
+
+ xmsg.to = new JID("juick", "s2s.juick.com", null);
+ xmpp.send(xmsg);
+
+ xmsg.to.Host = "ws.juick.com";
+ xmpp.send(xmsg);
+
+ xmsg.to.Host = "push.juick.com";
+ xmpp.send(xmsg);
+
+ xmsg.to.Host = "crosspost.juick.com";
+ xmsg.to.Username = "twitter";
+ xmpp.send(xmsg);
+ xmsg.to.Username = "fb";
+ xmpp.send(xmsg);
+
+ xmsg.to.Host = "nologin.ru";
+ xmsg.to.Username = "jubo";
+ xmpp.send(xmsg);
+ } else {
+ log("XMPP unavailable");
+ }
+ MessageSerializer serializer = new MessageSerializer();
+ Main.replyJSON(request, response, serializer.serialize(jmsg).toString());
+ }
+
+ public void doPostComment(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response, Stream xmpp, int vuid)
+ throws ServletException, IOException {
+ int mid = Utils.parseInt(request.getParameter("mid"), 0);
+ if (mid == 0) {
+ response.sendError(400);
+ return;
+ }
+ com.juick.Message msg = MessagesQueries.getMessage(sql, mid);
+ if (msg == null) {
+ response.sendError(404);
+ return;
+ }
+
+ int rid = Utils.parseInt(request.getParameter("rid"), 0);
+ com.juick.Message reply = null;
+ if (rid > 0) {
+ reply = MessagesQueries.getReply(sql, mid, rid);
+ if (reply == null) {
+ response.sendError(404);
+ return;
+ }
+ }
+
+ String body = request.getParameter("body");
+ if (body == null || body.length() < 1 || body.length() > 4096) {
+ response.sendError(400);
+ return;
+ }
+ body = body.replace("\r", "");
+
+ if ((msg.ReadOnly && msg.getUser().getUID() != vuid) || UserQueries.isInBLAny(sql, msg.getUser().getUID(), vuid)
+ || (reply != null && UserQueries.isInBLAny(sql, reply.getUser().getUID(), vuid))) {
+ response.sendError(403);
+ return;
+ }
+
+ String attachmentFName = null;
+ try {
+ attachmentFName = Utils.receiveMultiPartFile(request, "attach");
+ } catch (Exception e) {
+ System.out.println("MULTIPART ERROR: " + e.toString());
+ response.sendError(400);
+ return;
+ }
+
+ String paramImg = request.getParameter("img");
+ if (attachmentFName == null && paramImg != null && paramImg.length() > 10) {
+ try {
+ attachmentFName = Utils.downloadImage(new URL(paramImg));
+ } catch (Exception e) {
+ System.out.println("DOWNLOAD ERROR: " + e.toString());
+ response.sendError(500);
+ return;
+ }
+ }
+
+ String attachmentType = attachmentFName != null ? attachmentFName.substring(attachmentFName.length() - 3) : null;
+ int ridnew = MessagesQueries.createReply(sql, mid, rid, vuid, body, attachmentType);
+ SubscriptionsQueries.subscribeMessage(sql, mid, vuid);
+
+ JuickMessage jmsg = new JuickMessage(MessagesQueries.getReply(sql, mid, ridnew));
+
+ if (xmpp != null) {
+ Message xmsg = new Message();
+ xmsg.from = new JID("juick", "juick.com", null);
+ xmsg.type = Message.Type.chat;
+ xmsg.thread = "juick-" + mid;
+ xmsg.addChild(jmsg);
+
+ String quote = reply != null ? reply.getText() : msg.getText();
+ if (quote.length() >= 50) {
+ quote = quote.substring(0, 47) + "...";
+ }
+
+ Nickname nick = new Nickname();
+ nick.Nickname = "@" + jmsg.getUser().getUName();
+ xmsg.addChild(nick);
+
+ if (attachmentFName != null) {
+ String fname = mid + "-" + ridnew + "." + attachmentType;
+ String attachmentURL = "http://i.juick.com/photos-1024/" + fname;
+
+ Runtime.getRuntime().exec("/var/www/juick.com/cgi/p-convert.sh /var/www/juick.com/i/tmp/" + attachmentFName + " " + fname);
+
+ body = attachmentURL + "\n" + body;
+ XOOB xoob = new XOOB();
+ xoob.URL = attachmentURL;
+ xmsg.addChild(xoob);
+ }
+
+ xmsg.body = "Reply by @" + jmsg.getUser().getUName() + ":\n>" + quote + "\n" + body + "\n\n#" + mid + "/" + ridnew + " http://juick.com/" + mid + "#" + ridnew;
+
+ xmsg.to = new JID("juick", "s2s.juick.com", null);
+ xmpp.send(xmsg);
+
+ xmsg.to.Host = "ws.juick.com";
+ xmpp.send(xmsg);
+
+ xmsg.to.Host = "push.juick.com";
+ xmpp.send(xmsg);
+ } else {
+ log("XMPP unavailable");
+ }
+ MessageSerializer serializer = new MessageSerializer();
+ Main.replyJSON(request, response, serializer.serialize(jmsg).toString());
+ }
+
+ public static void replyJSON(HttpServletRequest request, HttpServletResponse response, String json) throws IOException {
+ response.setContentType("application/json; charset=UTF-8");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+
+ String callback = request.getParameter("callback");
+ if (callback != null && (callback.length() > 64 || !callback.matches("[a-zA-Z0-9\\-\\_]+"))) {
+ callback = null;
+ }
+
+ try (PrintWriter out = response.getWriter()) {
+ if (callback != null) {
+ out.print(callback + "(");
+ out.print(json);
+ out.print(")");
+ } else {
+ out.print(json);
+ }
+ }
+ }
+}
diff --git a/juick-api/src/main/java/com/juick/api/Messages.java b/juick-api/src/main/java/com/juick/api/Messages.java
new file mode 100644
index 000000000..b7131c310
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/Messages.java
@@ -0,0 +1,188 @@
+package com.juick.api;
+
+import com.juick.Tag;
+import com.juick.User;
+import com.juick.json.MessageSerializer;
+import com.juick.server.MessagesQueries;
+import com.juick.server.TagQueries;
+import com.juick.server.UserQueries;
+import com.juick.xmpp.JID;
+import com.juick.xmpp.Message;
+import com.juick.xmpp.Stream;
+import com.juick.xmpp.extensions.JuickMessage;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ *
+ * @author ugnich
+ */
+public class Messages {
+
+ JdbcTemplate sql;
+
+ MessageSerializer messageSerializer = new MessageSerializer();
+
+ public Messages(JdbcTemplate sql) {
+ this.sql = sql;
+ }
+
+ void feedMessages(HttpServletRequest request, HttpServletResponse response, List<Integer> mids) throws IOException {
+ if (mids != null && !mids.isEmpty()) {
+ List<com.juick.Message> msgs = MessagesQueries.getMessages(sql, mids);
+ if (msgs != null && !msgs.isEmpty()) {
+ String json = messageSerializer.serializeList(msgs);
+ Main.replyJSON(request, response, json);
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ public void doGetHome(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ int before_mid = Utils.parseInt(request.getParameter("before_mid"), 0);
+
+ feedMessages(request, response, MessagesQueries.getMyFeed(sql, vuid, before_mid));
+
+ }
+
+ public void doGet(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ int before_mid = Utils.parseInt(request.getParameter("before_mid"), 0);
+ String uname = request.getParameter("uname");
+ String popular = request.getParameter("popular");
+ String media = request.getParameter("media");
+ String tag = request.getParameter("tag");
+ if (!StringUtils.isEmpty(uname)) {
+ User user = UserQueries.getUserByName(sql, uname);
+ if (user != null) {
+ if (!StringUtils.isEmpty(media)) {
+ feedMessages(request, response, MessagesQueries.getUserPhotos(sql, user.getUID(), 0, before_mid));
+ } else if (!StringUtils.isEmpty(tag)) {
+ Tag tagObject = TagQueries.getTag(sql, tag, false);
+ if (tagObject != null) {
+ feedMessages(request, response, MessagesQueries.getUserTag(sql, user.getUID(), tagObject.TID, 0, before_mid));
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ feedMessages(request, response, MessagesQueries.getUserBlog(sql, user.getUID(), 0, before_mid));
+ }
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ if (!StringUtils.isEmpty(popular)) {
+ feedMessages(request, response, MessagesQueries.getPopular(sql, vuid, before_mid));
+ } else if (!StringUtils.isEmpty(media)) {
+ feedMessages(request, response, MessagesQueries.getPhotos(sql, vuid, before_mid));
+ } else if (!StringUtils.isEmpty(tag)) {
+ Tag tagObject = TagQueries.getTag(sql, tag, false);
+ if (tagObject != null) {
+ feedMessages(request, response, MessagesQueries.getTag(sql, tagObject.TID, vuid, before_mid, 20));
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ feedMessages(request, response, MessagesQueries.getAll(sql, vuid, before_mid));
+ }
+ }
+ }
+
+ public void doThreadGet(HttpServletRequest request, HttpServletResponse response, int vuid) throws IOException {
+ int mid = Utils.parseInt(request.getParameter("mid"), 0);
+ com.juick.Message msg = MessagesQueries.getMessage(sql, mid);
+ if (msg != null) {
+ if (!MessagesQueries.canViewThread(sql, mid, vuid)) {
+ response.sendError(403);
+ } else {
+ List<com.juick.Message> replies = MessagesQueries.getReplies(sql, mid);
+ replies.add(0, msg);
+ String json = messageSerializer.serializeList(replies);
+ Main.replyJSON(request, response, json);
+ }
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ public void doGetRecommended(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ int before_mid = Utils.parseInt(request.getParameter("before_mid"), 0);
+
+ List<Integer> mids = MessagesQueries.getUserRecommendations(sql, vuid, before_mid);
+ if (mids != null && !mids.isEmpty()) {
+ List<com.juick.Message> msgs = MessagesQueries.getMessages(sql, mids);
+ if (msgs != null && !msgs.isEmpty()) {
+ String json = messageSerializer.serializeList(msgs);
+ Main.replyJSON(request, response, json);
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ public void doSetPrivacy(HttpServletRequest request,
+ HttpServletResponse response, Stream xmpp, int vuid)
+ throws ServletException, IOException {
+ int mid = Utils.parseInt(request.getParameter("mid"), 0);
+ com.juick.User user = MessagesQueries.getMessageAuthor(sql, mid);
+ if (user != null && user.getUID() == vuid && MessagesQueries.setMessagePrivacy(sql, mid)) {
+ Main.replyJSON(request, response, "{\"status\":\"ok\"}");
+ } else {
+ response.sendError(400);
+ }
+ }
+
+ public void doSetPopular(HttpServletRequest request,
+ HttpServletResponse response, Stream xmpp)
+ throws ServletException, IOException {
+ int mid = Utils.parseInt(request.getParameter("mid"), 0);
+ int popular = Utils.parseInt(request.getParameter("popular"), 0);
+
+ if (mid > 0) {
+ boolean ret = MessagesQueries.setMessagePopular(sql, mid, popular);
+
+ if (ret && popular == 2) {
+ try {
+ com.juick.Message m = MessagesQueries.getMessage(sql, mid);
+ if (m != null) {
+ Message msg = new Message();
+ msg.from = new JID("juick", "juick.com", null);
+ msg.to = new JID(null, "crosspost.juick.com", null);
+ JuickMessage jmsg = new JuickMessage(m);
+ jmsg.setUser(UserQueries.getUserByUID(sql, 11574).get());
+ msg.childs.add(jmsg);
+
+ msg.to.Username = "twitter";
+ xmpp.send(msg);
+ msg.to.Username = "fb";
+ xmpp.send(msg);
+ msg.to.Username = "vk";
+ xmpp.send(msg);
+ } else {
+ throw new Exception("Message not found");
+ }
+ } catch (Exception e) {
+ System.err.println("SETPOPULAR ERROR: " + e.toString());
+ }
+ }
+
+ Main.replyJSON(request, response, "{\"status\":\"ok\"}");
+ }
+ }
+}
diff --git a/juick-api/src/main/java/com/juick/api/Others.java b/juick-api/src/main/java/com/juick/api/Others.java
new file mode 100644
index 000000000..12849f902
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/Others.java
@@ -0,0 +1,53 @@
+package com.juick.api;
+
+import com.juick.User;
+import com.juick.json.UserSerializer;
+import com.juick.server.PMQueries;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.sql.Connection;
+import java.util.List;
+
+/**
+ *
+ * @author ugnich
+ */
+public class Others {
+
+ JdbcTemplate sql;
+
+ UserSerializer userSerializer = new UserSerializer();
+
+ public Others(JdbcTemplate sql) {
+ this.sql = sql;
+ }
+
+ public void doGetGroupsPMs(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ int cnt = 5;
+ try {
+ String cntStr = request.getParameter("cnt");
+ cnt = Integer.parseInt(cntStr);
+ if (cnt < 3) {
+ cnt = 3;
+ }
+ if (cnt > 10) {
+ cnt = 10;
+ }
+ } catch (Exception e) {
+ }
+
+ List<User> lastconv = PMQueries.getPMLastConversationsUsers(sql, vuid, cnt);
+ if (lastconv != null && !lastconv.isEmpty()) {
+ String json = "{\"pms\":" + userSerializer.serializeList(lastconv) + "}";
+ Main.replyJSON(request, response, json);
+ } else {
+ response.sendError(404);
+ }
+ }
+}
diff --git a/juick-api/src/main/java/com/juick/api/PM.java b/juick-api/src/main/java/com/juick/api/PM.java
new file mode 100644
index 000000000..631ae9780
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/PM.java
@@ -0,0 +1,109 @@
+package com.juick.api;
+
+import com.juick.json.MessageSerializer;
+import com.juick.server.PMQueries;
+import com.juick.server.UserQueries;
+import com.juick.xmpp.JID;
+import com.juick.xmpp.Message;
+import com.juick.xmpp.Stream;
+import com.juick.xmpp.extensions.JuickMessage;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.io.IOException;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author ugnich
+ */
+public class PM {
+
+ JdbcTemplate sql;
+
+ MessageSerializer messageSerializer = new MessageSerializer();
+
+ public PM(JdbcTemplate sql) {
+ this.sql = sql;
+ }
+
+ public void doGetPM(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ String uname = request.getParameter("uname");
+ int uid = 0;
+ if (uname != null && uname.matches("^[a-zA-Z0-9\\-]{2,16}$")) {
+ uid = UserQueries.getUIDbyName(sql, uname);
+ }
+
+ if (uid == 0) {
+ response.sendError(400);
+ return;
+ }
+
+ List<com.juick.Message> msgs = PMQueries.getPMMessages(sql, vuid, uid);
+ if (msgs != null && !msgs.isEmpty()) {
+ String json = messageSerializer.serializeList(msgs);
+ Main.replyJSON(request, response, json);
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ public void doPostPM(HttpServletRequest request,
+ HttpServletResponse response, Stream xmpp, int vuid)
+ throws ServletException, IOException {
+ String uname = request.getParameter("uname");
+ int uid = 0;
+ if (UserQueries.checkUserNameValid(uname)) {
+ uid = UserQueries.getUIDbyName(sql, uname);
+ }
+
+ String body = request.getParameter("body");
+ if (uid == 0 || body == null || body.length() < 1 || body.length() > 10240) {
+ response.sendError(400);
+ return;
+ }
+
+ if (UserQueries.isInBLAny(sql, uid, vuid)) {
+ response.sendError(403);
+ return;
+ }
+
+ if (PMQueries.createPM(sql, vuid, uid, body)) {
+ Message msg = new Message();
+ msg.from = new JID("juick", "juick.com", null);
+ msg.to = new JID(Integer.toString(uid), "push.juick.com", null);
+ JuickMessage jmsg = new JuickMessage();
+ jmsg.setUser(UserQueries.getUserByUID(sql, vuid).get());
+ jmsg.setText(body);
+ msg.childs.add(jmsg);
+ xmpp.send(msg);
+
+ msg.to.Host = "ws.juick.com";
+ xmpp.send(msg);
+
+ Main.replyJSON(request, response, messageSerializer.serialize(jmsg).toString());
+
+ List<String> jids = UserQueries.getJIDsbyUID(sql, uid);
+ for (String jid: jids) {
+ Message mm = new Message();
+ mm.to = new JID(jid);
+ mm.type = Message.Type.chat;
+ if (PMQueries.havePMinRoster(sql, vuid, jid)) {
+ mm.from = new JID(jmsg.getUser().getUName(), "juick.com", "Juick");
+ mm.body = body;
+ } else {
+ mm.from = new JID("juick", "juick.com", "Juick");
+ mm.body = "Private message from @" + jmsg.getUser().getUName() + ":\n" + body;
+ }
+ xmpp.send(mm);
+ }
+
+ } else {
+ response.sendError(500);
+ }
+ }
+}
diff --git a/juick-api/src/main/java/com/juick/api/TelegramBotHook.java b/juick-api/src/main/java/com/juick/api/TelegramBotHook.java
new file mode 100644
index 000000000..e1094ff65
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/TelegramBotHook.java
@@ -0,0 +1,243 @@
+package com.juick.api;
+
+import com.juick.User;
+import com.juick.json.MessageSerializer;
+import com.juick.server.MessagesQueries;
+import com.juick.server.UserQueries;
+import com.neovisionaries.ws.client.*;
+import com.pengrad.telegrambot.BotUtils;
+import com.pengrad.telegrambot.Callback;
+import com.pengrad.telegrambot.TelegramBot;
+import com.pengrad.telegrambot.TelegramBotAdapter;
+import com.pengrad.telegrambot.model.Message;
+import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
+import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;
+import com.pengrad.telegrambot.request.SendMessage;
+import com.pengrad.telegrambot.response.SendResponse;
+import org.json.JSONObject;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Created by vt on 12/05/16.
+ */
+public class TelegramBotHook {
+ private static final Logger logger = Logger.getLogger(TelegramBotHook.class.getName());
+
+ TelegramBot bot;
+ WebSocket ws, wsReply;
+ MessageSerializer ms = new MessageSerializer();
+ JdbcTemplate jdbc;
+
+
+ public TelegramBotHook(JdbcTemplate jdbc, String token) {
+ this.jdbc = jdbc;
+ bot = TelegramBotAdapter.build(token);
+ bot.setWebhook("https://api.juick.com/tlgmbtwbhk");
+ try {
+ ws = new WebSocketFactory().createSocket("wss://ws.juick.com/_all");
+ ws.addHeader("Origin", "ws.juick.com");
+ ws.addHeader("Host", "ws.juick.com"); //TODO: remove from server
+ ws.setPingInterval(60 * 1000);
+ ws.addListener(new WebSocketAdapter() {
+ @Override
+ public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
+ logger.info("ws disconnected");
+ ws.connect();
+ }
+
+ @Override
+ public void onConnected(WebSocket websocket, Map<String, List<String>> headers) {
+ logger.info("ws connected");
+ }
+
+ @Override
+ public void onTextMessage(WebSocket websocket, String text) throws Exception {
+ super.onTextMessage(websocket, text);
+ com.juick.Message jmsg = ms.deserialize(new JSONObject(text));
+ logger.info("got jmsg: " + ms.serialize(jmsg).toString());
+ StringBuilder sb = new StringBuilder();
+ sb.append("@").append(jmsg.getUser().getUName()).append(":\n")
+ .append(jmsg.getTagsString()).append("\n").append(jmsg.getText()).append("\n");
+ if (jmsg.Photo != null) {
+ sb.append(jmsg.Photo);
+ }
+ String msg = sb.toString();
+ List<Long> users = getSubscribers(jmsg.getUser().getUID());
+ List<Long> chats = getChats();
+ // registered subscribed users
+ String msgUrl = "https://juick.com/" + jmsg.getMID();
+ users.stream().forEach(c -> telegramNotify(c, msg, msgUrl));
+ // anonymous
+ chats.stream().filter(u -> getUser(u) == 0).forEach(c -> telegramNotify(c, msg, msgUrl));
+ }
+ });
+ ws.connect();
+ wsReply = new WebSocketFactory().createSocket("wss://ws.juick.com/_replies");
+ wsReply.addHeader("Origin", "ws.juick.com");
+ wsReply.addHeader("Host", "ws.juick.com");
+ wsReply.setPingInterval(60 * 1000);
+ wsReply.addListener(new WebSocketAdapter() {
+ @Override
+ public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
+ logger.info("ws replies disconnected");
+ ws.connect();
+ }
+
+ @Override
+ public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
+ logger.info("ws replies connected");
+ }
+
+ @Override
+ public void onTextMessage(WebSocket websocket, String text) throws Exception {
+ com.juick.Message jmsg = ms.deserialize(new JSONObject(text));
+ logger.info(String.format("got jmsg: %s", ms.serialize(jmsg).toString()));
+ StringBuilder sb = new StringBuilder();
+ sb.append("Reply by @").append(jmsg.getUser().getUName()).append(":\n")
+ .append(getReplyQuote(jmsg.getMID(), jmsg.ReplyTo)).append("\n").append(jmsg.getText());
+ if (jmsg.getAttachmentURL() != null) {
+ sb.append("\n").append(jmsg.getAttachmentURL());
+ }
+ String msg = sb.toString();
+ String msgUrl = String.format("https://juick.com/%d#%d", jmsg.getMID(), jmsg.getRID());
+ getSubscribersToComments(jmsg.getMID(), jmsg.getUser().getUID()).stream()
+ .forEach(c -> telegramNotify(c, msg, msgUrl));
+ }
+ });
+ wsReply.connect();
+ } catch (IOException | WebSocketException e) {
+ logger.log(Level.SEVERE, "couldn't create ws connection", e);
+ }
+ }
+
+ private void telegramNotify(Long c, String msg, String msgUrl) {
+ bot.execute(new SendMessage(c, msg).replyMarkup(
+ new InlineKeyboardMarkup(
+ new InlineKeyboardButton[]{
+ new InlineKeyboardButton("See on Juick").url(msgUrl)
+ }
+ )), new Callback<SendMessage, SendResponse>() {
+ @Override
+ public void onResponse(SendMessage request, SendResponse response) {
+ logger.info("got response: " + response.message().toString());
+ }
+
+ @Override
+ public void onFailure(SendMessage request, IOException e) {
+ logger.log(Level.WARNING, "telegram failure", e);
+ }
+ });
+ }
+
+ List<Long> getChats() {
+ return jdbc.queryForList("SELECT chat_id FROM telegram_chats", Long.class);
+ }
+
+ void addChat(Long id) {
+ jdbc.update("INSERT IGNORE INTO telegram_chats(chat_id) VALUES(?)", id);
+ }
+
+ public void doPost(HttpServletRequest request) throws IOException {
+ try (BufferedReader reader = request.getReader()) {
+ Message message = BotUtils.parseUpdate(reader).message();
+ User user_from = UserQueries.getUserByUID(jdbc, getUser(message.chat().id())).orElse(new User());
+ logger.info(String.format("got telegram msg %s from juick user %d", message.toString(), user_from.getUID()));
+ List<Long> chats = getChats();
+ String username = message.from().username();
+ if (username == null) {
+ username = message.from().firstName();
+ }
+ if (!chats.contains(message.chat().id())) {
+ addChat(message.chat().id());
+ logger.info("added chat with " + username);
+ createTelegramUser(message.from().id(), username);
+ telegramSignupNotify(message.from().id().longValue(), UserQueries.getSignUpHashByTelegramID(jdbc, message.from().id().longValue(), username));
+ } else {
+ if (user_from.getUID() == 0) {
+ telegramSignupNotify(message.from().id().longValue(), UserQueries.getSignUpHashByTelegramID(jdbc, message.from().id().longValue(), username));
+ } else if (message.text().equalsIgnoreCase("/login")) {
+ String msg = String.format("Hi, %s!\nTap to log in", user_from.getUName());
+ String msgUrl = "http://juick.com/login?" + UserQueries.getHashByUID(jdbc, user_from.getUID());
+ telegramNotify(message.from().id().longValue(), msg, msgUrl);
+ }
+ }
+ }
+ }
+
+ private void telegramSignupNotify(Long telegramId, String hash) {
+ bot.execute(new SendMessage(telegramId,
+ "You are subscribed to all Juick messages. " +
+ "Create or link an existing Juick account to control " +
+ "what do you want to receive").replyMarkup(
+ new InlineKeyboardMarkup(
+ new InlineKeyboardButton[]{
+ new InlineKeyboardButton("SIGNUP").url("http://juick.com/signup?type=durov&hash=" +
+ hash)
+ })), new Callback<SendMessage, SendResponse>() {
+ @Override
+ public void onResponse(SendMessage request, SendResponse response) {
+ logger.info("got response: " + response.message().toString());
+ }
+
+ @Override
+ public void onFailure(SendMessage request, IOException e) {
+ logger.log(Level.WARNING, "telegram failure", e);
+ }
+ });
+ }
+
+ private boolean createTelegramUser(long tgID, String tgName) {
+ return jdbc.update("INSERT INTO telegram(tg_id, tg_name, loginhash) VALUES(?,?,?)",
+ tgID, tgName, UUID.randomUUID().toString()) > 0;
+ }
+
+ private int getUser(long tgId) {
+ try {
+ return jdbc.queryForObject("SELECT id FROM users INNER JOIN telegram " +
+ "ON telegram.user_id = users.id WHERE telegram.tg_id=?", Integer.class, tgId);
+ } catch (EmptyResultDataAccessException e) {
+ return 0;
+ }
+ }
+
+ private List<Long> getSubscribers(int uid) {
+ return jdbc.queryForList("SELECT tg_id FROM telegram INNER JOIN subscr_users " +
+ "ON (subscr_users.user_id=? AND telegram.user_id=subscr_users.suser_id)", Long.class, uid);
+ }
+
+ private List<Long> getSubscribersToComments(int mid, int ignore_uid) {
+ return jdbc.queryForList("SELECT tg_id FROM telegram INNER JOIN subscr_messages " +
+ "ON (telegram.user_id=subscr_messages.suser_id) WHERE message_id=? AND suser_id!=?", Long.class, mid, ignore_uid);
+ }
+
+ private String getReplyQuote(int MID, int ReplyTo) {
+ String quote = "";
+ if (ReplyTo > 0) {
+ com.juick.Message q = MessagesQueries.getReply(jdbc, MID, ReplyTo);
+ if (q != null) {
+ quote = q.getText();
+ }
+ } else {
+ com.juick.Message q = MessagesQueries.getMessage(jdbc, MID);
+ if (q != null) {
+ quote = q.getText();
+ }
+ }
+ if (quote.length() > 50) {
+ quote = ">" + quote.substring(0, 47).replace('\n', ' ') + "...\n";
+ } else if (quote.length() > 0) {
+ quote = ">" + quote.replace('\n', ' ') + "\n";
+ }
+ return quote;
+ }
+}
diff --git a/juick-api/src/main/java/com/juick/api/Users.java b/juick-api/src/main/java/com/juick/api/Users.java
new file mode 100644
index 000000000..e85c517a9
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/Users.java
@@ -0,0 +1,126 @@
+package com.juick.api;
+
+import com.juick.User;
+import com.juick.json.UserSerializer;
+import com.juick.server.UserQueries;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ *
+ * @author ugnich
+ */
+public class Users {
+
+ JdbcTemplate sql;
+
+ UserSerializer userSerializer = new UserSerializer();
+
+ public Users(JdbcTemplate sql) {
+ this.sql = sql;
+ }
+
+ public void doGetUsers(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ List<com.juick.User> users = new ArrayList<>();
+
+ String punames[] = request.getParameterValues("uname");
+ if (punames != null) {
+ ArrayList<String> unames = new ArrayList<>(Arrays.asList(punames));
+ Iterator<String> i = unames.iterator();
+ while (i.hasNext()) {
+ if (!i.next().matches("^[a-zA-Z0-9\\-]{2,16}$")) {
+ i.remove();
+ }
+ }
+ if (!unames.isEmpty() && unames.size() < 20) {
+ users.addAll(UserQueries.getUsersByName(sql, unames));
+ }
+ }
+
+ String pjids[] = request.getParameterValues("jid");
+ if (pjids != null) {
+ List<String> jids = new ArrayList<>(Arrays.asList(pjids));
+ Iterator<String> ii = jids.iterator();
+ while (ii.hasNext()) {
+ if (!ii.next().matches("^[a-zA-Z0-9\\-\\_\\@\\.]{6,64}$")) {
+ ii.remove();
+ }
+ }
+ if (!jids.isEmpty() && jids.size() < 20) {
+ users.addAll(UserQueries.getUsersByJID(sql, jids));
+ }
+ }
+
+ if (!users.isEmpty()) {
+ String json = userSerializer.serializeList(users);
+ Main.replyJSON(request, response, json);
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ public void doGetUserRead(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ int uid = 0;
+ String uname = request.getParameter("uname");
+ if (uname == null) {
+ uid = vuid;
+ } else {
+ if (UserQueries.checkUserNameValid(uname)) {
+ com.juick.User u = UserQueries.getUserByName(sql, uname);
+ if (u != null && u.getUID() > 0) {
+ uid = u.getUID();
+ }
+ }
+ }
+
+ if (uid > 0) {
+ List<Integer> uids = UserQueries.getUserRead(sql, uid);
+ if (uids.size() > 0) {
+ List<com.juick.User> users = UserQueries.getUsersByID(sql, uids);
+ if (users.size() > 0) {
+ String json = userSerializer.serializeList(users);
+ Main.replyJSON(request, response, json);
+ return;
+ }
+ }
+ }
+ response.sendError(404);
+ }
+
+ public void doGetUserReaders(HttpServletRequest request,
+ HttpServletResponse response, int vuid)
+ throws ServletException, IOException {
+ int uid = 0;
+ String uname = request.getParameter("uname");
+ if (uname == null) {
+ uid = vuid;
+ } else {
+ if (UserQueries.checkUserNameValid(uname)) {
+ com.juick.User u = UserQueries.getUserByName(sql, uname);
+ if (u != null && u.getUID() > 0) {
+ uid = u.getUID();
+ }
+ }
+ }
+
+ if (uid > 0) {
+ List<User> users = UserQueries.getUserReaders(sql, uid);
+ String json = userSerializer.serializeList(users);
+ Main.replyJSON(request, response, json);
+ return;
+ }
+ response.sendError(404);
+ }
+}
diff --git a/juick-api/src/main/java/com/juick/api/Utils.java b/juick-api/src/main/java/com/juick/api/Utils.java
new file mode 100644
index 000000000..ca0518e1a
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/Utils.java
@@ -0,0 +1,231 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.juick.api;
+
+import com.juick.server.UserQueries;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.UUID;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Utils {
+
+ public static String getCookie(HttpServletRequest request, String name) {
+ Cookie cookies[] = request.getCookies();
+ if (cookies != null) {
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(name)) {
+ return cookies[i].getValue();
+ }
+ }
+ }
+ return null;
+ }
+
+ public static com.juick.User getVisitorUser(JdbcTemplate sql, HttpServletRequest request) {
+ String hash = getCookie(request, "hash");
+ if (hash != null) {
+ return com.juick.server.UserQueries.getUserByHash(sql, hash);
+ } else {
+ return null;
+ }
+ }
+
+ public static int getVisitorUID(JdbcTemplate sql, HttpServletRequest request) {
+ Cookie cookies[] = request.getCookies();
+ if (cookies != null) {
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals("hash")) {
+ String hash = cookies[i].getValue();
+ return com.juick.server.UserQueries.getUIDbyHash(sql, hash);
+ }
+ }
+ }
+ return 0;
+ }
+
+ public static int getHttpAuthUID(JdbcTemplate sql, HttpServletRequest request) {
+ String auth = request.getHeader("Authorization");
+ if (auth != null && auth.length() > 8 && auth.startsWith("Basic ")) {
+ Base64.Decoder dec = Base64.getDecoder();
+ String loginpassw[] = new String(dec.decode(auth.substring(6))).split(":", 2);
+ if (loginpassw.length == 2 && loginpassw[0].length() > 1 && loginpassw[0].length() < 16 && loginpassw[0].matches("[a-zA-Z0-9\\-]+") && !loginpassw[1].isEmpty()) {
+ return UserQueries.checkPassword(sql, loginpassw[0], loginpassw[1]);
+ }
+ }
+ return 0;
+ }
+
+ public static int getVisitorQueryStringUID(JdbcTemplate sql, HttpServletRequest request) {
+ String hash = request.getParameter("hash");
+ if (hash != null && hash.length() == 16) {
+ return com.juick.server.UserQueries.getUIDbyHash(sql, hash);
+ }
+ return 0;
+ }
+
+ public static void sendPermanentRedirect(HttpServletResponse response, String location) {
+ response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
+ response.setHeader("Location", location);
+ }
+
+ public static void finishSQL(ResultSet rs, Statement stmt) {
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (stmt != null) {
+ try {
+ stmt.close();
+ } catch (SQLException e) {
+ }
+ }
+ }
+
+ public static String convertArray2String(ArrayList<Integer> mids) {
+ String q = "";
+ for (int i = 0; i < mids.size(); i++) {
+ if (i > 0) {
+ q += ",";
+ }
+ q += mids.get(i);
+ }
+ return q;
+ }
+
+ public static String encodeHTML(String str) {
+ String ret = str;
+ ret = ret.replaceAll("<", "&lt;");
+ ret = ret.replaceAll(">", "&gt;");
+ return str;
+ }
+
+ public static String encodeSphinx(String str) {
+ String ret = str;
+ ret = ret.replaceAll("@", "\\\\@");
+ return ret;
+ }
+
+ public static int parseInt(String str, int def) {
+ int ret = def;
+ if (str != null) {
+ try {
+ ret = Integer.parseInt(str);
+ } catch (Exception e) {
+ }
+ }
+ return ret;
+ }
+ public static String getPartFilename(Part part) {
+ for (String cd : part.getHeader("content-disposition").split(";")) {
+ if (cd.trim().startsWith("filename")) {
+ String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
+ return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
+ }
+ }
+ return null;
+ }
+ public static String receiveMultiPartFile(HttpServletRequest request, String name) throws Exception {
+ String attachmentFName = null;
+
+ Part filePart = request.getPart("attach");
+ if (filePart != null) {
+ String partname = Utils.getPartFilename(filePart);
+ if (partname != null && partname.length() > 0) {
+ String attachmentType = partname.substring(partname.length() - 3).toLowerCase();
+ if (attachmentType.equals("jpg") || attachmentType.equals("peg") || attachmentType.equals("png")) {
+ if (attachmentType.equals("peg")) {
+ attachmentType = "jpg";
+ }
+ attachmentFName = UUID.randomUUID().toString() + "." + attachmentType;
+ filePart.write("/var/www/juick.com/i/tmp/" + attachmentFName);
+ } else {
+ throw new Exception("Wrong file type");
+ }
+ }
+ }
+
+ return attachmentFName;
+ }
+ public static String downloadImage(URL url) throws Exception {
+ String attachmentFName = null;
+ Exception ex = null;
+
+ InputStream is = null;
+ FileOutputStream fos = null;
+ try {
+ URLConnection urlConn = url.openConnection();
+ is = urlConn.getInputStream();
+ String mime = urlConn.getContentType();
+
+ String attachmentType;
+ if (mime != null && mime.equals("image/jpeg")) {
+ attachmentType = "jpg";
+ } else if (mime != null && mime.equals("image/png")) {
+ attachmentType = "png";
+ } else {
+ throw new Exception("Wrong file type");
+ }
+
+ attachmentFName = UUID.randomUUID().toString() + "." + attachmentType;
+ fos = new FileOutputStream("/var/www/juick.com/i/tmp/" + attachmentFName);
+ byte[] buffer = new byte[10240];
+ int len;
+ while ((len = is.read(buffer)) > 0) {
+ fos.write(buffer, 0, len);
+ }
+ } catch (Exception e) {
+ ex = e;
+ attachmentFName = null;
+ } finally {
+ try {
+ if (is != null) {
+ is.close();
+ }
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+
+ if (ex != null) {
+ throw ex;
+ } else {
+ return attachmentFName;
+ }
+ }
+}
diff --git a/juick-api/src/main/webapp/WEB-INF/juick.conf.example b/juick-api/src/main/webapp/WEB-INF/juick.conf.example
new file mode 100644
index 000000000..61ebbc294
--- /dev/null
+++ b/juick-api/src/main/webapp/WEB-INF/juick.conf.example
@@ -0,0 +1,6 @@
+datasource_driver=org.h2.Driver
+datasource_url=jdbc:h2:~/test
+xmpp_host=localhost
+xmpp_port=5347
+xmpp_jid=api.localhost
+xmpp_password=secret \ No newline at end of file
diff --git a/juick-api/src/main/webapp/WEB-INF/web.xml b/juick-api/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..533a68828
--- /dev/null
+++ b/juick-api/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
+ <servlet>
+ <servlet-name>Main</servlet-name>
+ <servlet-class>com.juick.api.Main</servlet-class>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>Main</servlet-name>
+ <url-pattern>/</url-pattern>
+ </servlet-mapping>
+ <session-config>
+ <session-timeout>
+ 30
+ </session-timeout>
+ </session-config>
+</web-app>