aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Ugnich Anton2012-01-27 08:31:23 +0700
committerGravatar Ugnich Anton2012-01-27 08:31:23 +0700
commita0e43fc8a853a71b6aa85f93843c1692a4d13708 (patch)
tree9790fb04141a30073038262ceb3546fdf4d1b678 /src
parent6f4e181f0a03b4b190922bd5f8bd97fb9fdb206e (diff)
SAPE, NewMessage (GET)
Diffstat (limited to 'src')
-rw-r--r--src/java/Global.properties2
-rw-r--r--src/java/Global_ru.properties2
-rw-r--r--src/java/NewMessage.properties13
-rw-r--r--src/java/NewMessage_ru.properties14
-rw-r--r--src/java/com/juick/http/www/Blogs.java2
-rw-r--r--src/java/com/juick/http/www/Chats.java2
-rw-r--r--src/java/com/juick/http/www/Login.java9
-rw-r--r--src/java/com/juick/http/www/Main.java43
-rw-r--r--src/java/com/juick/http/www/Map.java2
-rw-r--r--src/java/com/juick/http/www/NewMessage.java88
-rw-r--r--src/java/com/juick/http/www/PageTemplates.java25
-rw-r--r--src/java/com/juick/http/www/Photos.java2
-rw-r--r--src/java/com/juick/http/www/User.java2
-rw-r--r--src/java/com/juick/http/www/UserThread.java62
-rw-r--r--src/java/com/juick/http/www/Utils.java2
-rw-r--r--src/java/ru/sape/Sape.java25
-rw-r--r--src/java/ru/sape/SapeConnection.java107
-rw-r--r--src/java/ru/sape/SapePageLinks.java95
-rw-r--r--src/java/ru/sape/SerializedPhpParser.java221
19 files changed, 678 insertions, 40 deletions
diff --git a/src/java/Global.properties b/src/java/Global.properties
index 0883bec5..ebede501 100644
--- a/src/java/Global.properties
+++ b/src/java/Global.properties
@@ -15,3 +15,5 @@ Help=Help
Older=Older
Newer=Newer
(replies)\ by=by
+Comment=Comment
+Sponsored\ by=Sponsored by
diff --git a/src/java/Global_ru.properties b/src/java/Global_ru.properties
index 81ba9c4f..34d7418a 100644
--- a/src/java/Global_ru.properties
+++ b/src/java/Global_ru.properties
@@ -15,3 +15,5 @@ Help=\u0421\u043f\u0440\u0430\u0432\u043a\u0430
Older=\u0421\u0442\u0430\u0440\u044b\u0435
Newer=\u041d\u043e\u0432\u044b\u0435
(replies)\ by=\u043e\u0442
+Comment=\u041e\u0442\u0432\u0435\u0442\u0438\u0442\u044c
+Sponsored\ by=\u041f\u0440\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435
diff --git a/src/java/NewMessage.properties b/src/java/NewMessage.properties
new file mode 100644
index 00000000..93d91111
--- /dev/null
+++ b/src/java/NewMessage.properties
@@ -0,0 +1,13 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+New\ message=New message
+Location=Location
+Clear=Clear
+Attachment=Attachment
+from\ webcam=from webcam
+Webcam\ photo=Webcam photo
+Post=Post
+Tags=Tags
+Photo_JPG=Photo: JPG, up to 10Mb. Video: MP4/3GP/MOV/WMV/AVI/M4V, up to 100Mb.
+or=or
diff --git a/src/java/NewMessage_ru.properties b/src/java/NewMessage_ru.properties
new file mode 100644
index 00000000..bb61fe23
--- /dev/null
+++ b/src/java/NewMessage_ru.properties
@@ -0,0 +1,14 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+New\ message=\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435
+Location=\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+Clear=\u0423\u0434\u0430\u043b\u0438\u0442\u044c
+Attachment=\u0424\u0430\u0439\u043b
+
+from\ webcam=\u0441 \u0432\u0435\u0431\u043a\u0430\u043c\u0435\u0440\u044b
+Webcam\ photo=\u0424\u043e\u0442\u043e \u0441 \u0432\u0435\u0431\u043a\u0430\u043c\u0435\u0440\u044b
+Post=\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c
+Tags=\u0422\u0435\u0433\u0438
+Photo_JPG=\u0424\u043e\u0442\u043e: JPG, \u0434\u043e 10\u041c\u0431. \u0412\u0438\u0434\u0435\u043e: MP4/3GP/MOV/WMV/AVI/M4V, \u0434\u043e 100Mb.
+or=\u0438\u043b\u0438
diff --git a/src/java/com/juick/http/www/Blogs.java b/src/java/com/juick/http/www/Blogs.java
index 3b9b6882..b4d30de0 100644
--- a/src/java/com/juick/http/www/Blogs.java
+++ b/src/java/com/juick/http/www/Blogs.java
@@ -160,7 +160,7 @@ public class Blogs {
out.println("</div>");
out.println("</div>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
diff --git a/src/java/com/juick/http/www/Chats.java b/src/java/com/juick/http/www/Chats.java
index 3df37976..d15bb271 100644
--- a/src/java/com/juick/http/www/Chats.java
+++ b/src/java/com/juick/http/www/Chats.java
@@ -69,7 +69,7 @@ public class Chats {
out.println("</ul></div>");
out.println("</div>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
diff --git a/src/java/com/juick/http/www/Login.java b/src/java/com/juick/http/www/Login.java
index d03dd64d..1baf6e43 100644
--- a/src/java/com/juick/http/www/Login.java
+++ b/src/java/com/juick/http/www/Login.java
@@ -57,7 +57,7 @@ public class Login {
out.println("</div>");
out.println("</div>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
@@ -98,7 +98,12 @@ public class Login {
c.setMaxAge(0);
response.addCookie(c);
- response.sendRedirect("/");
+ String referer = request.getHeader("Referer");
+ if (referer != null && referer.startsWith("http://juick.com/") && !referer.equals("http://juick.com/login")) {
+ response.sendRedirect(referer);
+ } else {
+ response.sendRedirect("/");
+ }
} else {
response.sendError(403);
}
diff --git a/src/java/com/juick/http/www/Main.java b/src/java/com/juick/http/www/Main.java
index 709c6588..b7f95a4a 100644
--- a/src/java/com/juick/http/www/Main.java
+++ b/src/java/com/juick/http/www/Main.java
@@ -17,6 +17,7 @@
*/
package com.juick.http.www;
+import com.juick.xmpp.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
@@ -28,16 +29,18 @@ import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import ru.sape.Sape;
/**
*
* @author Ugnich Anton
*/
@WebServlet(name = "Main", urlPatterns = {"/"})
-public class Main extends HttpServlet {
+public class Main extends HttpServlet implements XmppListener {
Connection sql;
Connection sqlSearch;
+ XmppConnection xmpp;
Blogs blogs = new Blogs();
Chats chats = new Chats();
Photos photos = new Photos();
@@ -58,6 +61,13 @@ public class Main extends HttpServlet {
Class.forName("com.mysql.jdbc.Driver");
sql = DriverManager.getConnection("jdbc:mysql://localhost/juick?autoReconnect=true&user=" + conf.getProperty("mysql_username", "") + "&password=" + conf.getProperty("mysql_password", ""));
sqlSearch = DriverManager.getConnection("jdbc:mysql://127.0.0.1:9306/juick?autoReconnect=true&characterEncoding=utf8&maxAllowedPacket=512000&relaxAutoCommit=true&user=root&password=");
+ /*
+ xmpp = new XmppConnectionComponent(new JID("www.juick.com"), conf.getProperty("xmpp_password", ""), "127.0.0.1", 5347, false);
+ xmpp.addListener((XmppListener) this);
+ xmpp.start();
+ */
+
+ PageTemplates.sape = new Sape(conf.getProperty("sape_user"), "juick.com", 2000, 3600);
} catch (Exception e) {
log(null, e);
}
@@ -69,10 +79,34 @@ public class Main extends HttpServlet {
if (sql != null) {
try {
sql.close();
+ sql = null;
} catch (SQLException e) {
log(null, e);
}
}
+ if (sqlSearch != null) {
+ try {
+ sqlSearch.close();
+ sqlSearch = null;
+ } catch (SQLException e) {
+ log(null, e);
+ }
+ }
+ }
+
+ @Override
+ public void onAuth(String resource) {
+ log("XMPP AUTH: " + resource);
+ }
+
+ @Override
+ public void onAuthFailed(String message) {
+ log("XMPP AUTH FAILED: " + message);
+ }
+
+ @Override
+ public void onConnectionFailed(String message) {
+ log("XMPP CONNECTION FAILED: " + message);
}
/**
@@ -97,7 +131,12 @@ public class Main extends HttpServlet {
} else if (uri.equals("/map")) {
map.doGet(sql, request, response);
} else if (uri.equals("/post")) {
- pagesNewMessage.doGetNewMessage(sql, request, response);
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ if (visitor != null) {
+ pagesNewMessage.doGetNewMessage(sql, request, response, visitor);
+ } else {
+ login.doGetLoginForm(sql, request, response);
+ }
} else if (uri.equals("/login")) {
if (request.getQueryString() == null) {
login.doGetLoginForm(sql, request, response);
diff --git a/src/java/com/juick/http/www/Map.java b/src/java/com/juick/http/www/Map.java
index 1bc625b8..96524ac0 100644
--- a/src/java/com/juick/http/www/Map.java
+++ b/src/java/com/juick/http/www/Map.java
@@ -56,7 +56,7 @@ public class Map {
out.println("$(window).unload(GUnload);");
out.println("</script>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
diff --git a/src/java/com/juick/http/www/NewMessage.java b/src/java/com/juick/http/www/NewMessage.java
index 8a92b475..1beacf62 100644
--- a/src/java/com/juick/http/www/NewMessage.java
+++ b/src/java/com/juick/http/www/NewMessage.java
@@ -17,8 +17,16 @@
*/
package com.juick.http.www;
+import com.juick.Tag;
+import com.juick.server.TagQueries;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.ResourceBundle;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -29,7 +37,85 @@ import javax.servlet.http.HttpServletResponse;
*/
public class NewMessage {
- protected void doGetNewMessage(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ protected void doGetNewMessage(Connection sql, HttpServletRequest request, HttpServletResponse response, com.juick.User visitor) throws ServletException, IOException {
+ Locale locale = request.getLocale();
+ ResourceBundle rbnm = ResourceBundle.getBundle("NewMessage", locale);
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, rbnm.getString("New message"), "<script src=\"http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAVVtPtxkw4soCEHg44FsNChRB4OFYjAXt73He16Zkp6a_0tPs2RTU6i6UlcMs4QvPBYvIY8rWvcxqOg\" type=\"text/javascript\"></script>"
+ + "<script src=\"http://static.juick.com/mc.js\" type=\"text/javascript\"></script>"
+ + "<script src=\"http://static.juick.com/map.js?2010111500\" type=\"text/javascript\"></script>"
+ + "<script src=\"http://static.juick.com/post3.js\" type=\"text/javascript\"></script>");
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageTitle(out, rbnm.getString("New message"));
+
+ out.println("<div id=\"wrapper\"><div id=\"content\" class=\"pagetext\">");
+ out.println("<form action=\"/post\" method=\"post\" id=\"postmsg\" enctype=\"multipart/form-data\">");
+ out.println("<p style=\"text-align: left\"><b>" + rbnm.getString("Location") + ": <span id=\"location\"></span></b> <span id=\"locationclear\">&mdash; <a href=\"#\" onclick=\"clearLocation()\">" + rbnm.getString("Clear") + "</a></span></p>");
+ out.println("<p style=\"text-align: left\"><b>" + rbnm.getString("Attachment") + ":</b> <span id=\"attachmentfile\"><input type=\"file\" name=\"attach\"$canmedia/> " + rbnm.getString("or") + " <a href=\"#\" onclick=\"webcamShow(); return false;\">" + rbnm.getString("from webcam") + "</a><br/>");
+ out.println("<i>" + rbnm.getString("Photo_JPG") + "</i></span><span id=\"attachmentwebcam\">" + rbnm.getString("Webcam photo") + " &mdash; <a href=\"#\" onclick=\"clearAttachment(); return false;\">" + rbnm.getString("Clear") + "</a></span></p>");
+ out.println("<div id=\"webcamwrap\" style=\"width: 320px; margin: 0 auto\"><div id=\"webcam\"></div></div>");
+ out.println("<p><textarea name=\"body\" rows=\"7\" cols=\"10\">" + "" + "</textarea><br/>");
+ out.println("<input type=\"hidden\" name=\"place_id\"/><input type=\"hidden\" name=\"webcam\"/>" + "" + "<input type=\"submit\" class=\"subm\" value=\" " + rbnm.getString("Post") + " \"/></p>");
+ out.println("</form>");
+ out.println("<div id=\"geomap\"></div>");
+ out.println("<p style=\"text-align: left\"><b>" + rbnm.getString("Tags") + ":</b></p>");
+ printUserTags(sql, out, visitor.UID);
+ out.println("</div>");
+ out.println("</div>");
+
+ PageTemplates.pageFooter(request, out, locale, visitor);
+ } finally {
+ out.close();
+ }
+ }
+
+ void printUserTags(Connection sql, PrintWriter out, int uid) {
+ ArrayList<Tag> tags = TagQueries.getUserTagsAll(sql, uid);
+
+ if (tags.isEmpty()) {
+ return;
+ }
+
+ int min = tags.get(0).UsageCnt;
+ int max = tags.get(0).UsageCnt;
+ for (int i = 1; i < tags.size(); i++) {
+ int usagecnt = tags.get(i).UsageCnt;
+ if (usagecnt < min) {
+ min = usagecnt;
+ }
+ if (usagecnt > max) {
+ max = usagecnt;
+ }
+ }
+ max -= min;
+
+ out.print("<p style=\"text-align: justify\">");
+ for (int i = 0; i < tags.size(); i++) {
+ if (i > 0) {
+ out.print(" ");
+ }
+ String taglink = "";
+ try {
+ taglink = "<a onclick=\"return addTag('" + Utils.encodeHTML(tags.get(i).Name) + "')\" href=\"/?tag=" + URLEncoder.encode(tags.get(i).Name, "utf-8") + "\" title=\"" + tags.get(i).UsageCnt + "\">" + Utils.encodeHTML(tags.get(i).Name) + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+ int usagecnt = tags.get(i).UsageCnt;
+ if (usagecnt <= max / 5 + min) {
+ out.print("<span style=\"font-size: small\">" + taglink + "</span>");
+ } else if (usagecnt <= max / 5 * 2 + min) {
+ out.print(taglink);
+ } else if (usagecnt <= max / 5 * 3 + min) {
+ out.print("<span style=\"font-size: large\">" + taglink + "</span>");
+ } else if (usagecnt <= max / 5 * 4 + min) {
+ out.print("<span style=\"font-size: x-large\">" + taglink + "</span>");
+ } else {
+ out.print("<span style=\"font-size: xx-large\">" + taglink + "</span>");
+ }
+ }
+ out.println("</p>");
}
protected void doPostNewMessage(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
diff --git a/src/java/com/juick/http/www/PageTemplates.java b/src/java/com/juick/http/www/PageTemplates.java
index 94561dfd..eb98a4f8 100644
--- a/src/java/com/juick/http/www/PageTemplates.java
+++ b/src/java/com/juick/http/www/PageTemplates.java
@@ -27,6 +27,8 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.ResourceBundle;
+import javax.servlet.http.HttpServletRequest;
+import ru.sape.Sape;
/**
*
@@ -34,6 +36,8 @@ import java.util.ResourceBundle;
*/
public class PageTemplates {
+ public static Sape sape = null;
+
public static void pageHead(PrintWriter out, String title, String headers) {
out.println("<!DOCTYPE html>");
out.println("<html>");
@@ -61,7 +65,7 @@ public class PageTemplates {
out.println("<div id=\"logo\"><a href=\"/?show=my\"><img src=\"http://static.juick.com/logo3.png\" width=\"120\" height=\"40\" alt=\"Juick\" border=\"0\"/></a></div>");
out.println(" <ul id=\"nav\">");
out.println(" <li><a href=\"/\">" + rb.getString("Blogs") + "</a></li>");
- out.println(" <li><a href=\"/chats\">" + rb.getString("Chats") + "</a></li>");
+// out.println(" <li><a href=\"/chats\">" + rb.getString("Chats") + "</a></li>");
out.println(" <li><a href=\"/photos\">" + rb.getString("Photos") + "</a></li>");
out.println(" <li><a href=\"/map\">" + rb.getString("Map") + "</a></li>");
out.println(" </ul>");
@@ -187,11 +191,18 @@ public class PageTemplates {
out.println();
}
- public static void pageFooter(PrintWriter out, Locale loc) {
+ public static void pageFooter(HttpServletRequest request, PrintWriter out, Locale loc, com.juick.User visitor) {
ResourceBundle rb = ResourceBundle.getBundle("Global", loc);
out.println("<div id=\"fwrapper\"><div id=\"footer\">");
out.println(" <div id=\"footer-right\"><a href=\"/help/contacts\">" + rb.getString("Contacts") + "</a> &#183; <a href=\"/help/\">" + rb.getString("Help") + "</a></div>");
- out.println(" <div id=\"footer-left\">juick.com &copy; 2008-2011</div>");
+ out.print(" <div id=\"footer-left\">juick.com &copy; 2008-2012");
+ if (sape != null && visitor == null) {
+ String links = sape.getPageLinks(request.getRequestURI(), request.getCookies()).render();
+ if (links != null && !links.isEmpty()) {
+ out.print("<br/>" + rb.getString("Sponsored by") + ": " + links);
+ }
+ }
+ out.println("</div>");
out.println("</div>");
}
@@ -331,15 +342,15 @@ public class PageTemplates {
txt = formatMessage(txt);
+ out.print(" <li id=\"msg-" + mid + "\" class=\"msg\"");
if (mid == mids.get(0)) {
- out.println(" <li class=\"msg\" style=\"border: 0\">");
- } else {
- out.println(" <li class=\"msg\">");
+ out.print(" style=\"border: 0\"");
}
+ out.println(">");
if (rs.getString(12) != null) {
if (rs.getString(12).equals("jpg")) {
- out.println(" <div class=\"msg-media\"><img src=\"http://i.juick.com/photos-512/" + mid + ".jpg\" alt=\"\"/></div>");
+ out.println(" <div class=\"msg-media\"><a href=\"http://i.juick.com/photos-1024/" + mid + ".jpg\"><img src=\"http://i.juick.com/photos-512/" + mid + ".jpg\" alt=\"\"/></a></div>");
} else {
out.println(" <div class=\"msg-media\"><div id=\"video-" + mid + "\"><b>Attachment: <a href=\"http://i.juick.com/video/" + mid + ".mp4\">Video</a></b></div></div>");
out.println(" <script type=\"text/javascript\">");
diff --git a/src/java/com/juick/http/www/Photos.java b/src/java/com/juick/http/www/Photos.java
index 7a202625..a2665501 100644
--- a/src/java/com/juick/http/www/Photos.java
+++ b/src/java/com/juick/http/www/Photos.java
@@ -92,7 +92,7 @@ public class Photos {
out.println("});");
out.println("</script>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
diff --git a/src/java/com/juick/http/www/User.java b/src/java/com/juick/http/www/User.java
index fefe1174..9d692a44 100644
--- a/src/java/com/juick/http/www/User.java
+++ b/src/java/com/juick/http/www/User.java
@@ -140,7 +140,7 @@ public class User {
out.println("</div>");
out.println("</div>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
diff --git a/src/java/com/juick/http/www/UserThread.java b/src/java/com/juick/http/www/UserThread.java
index 6688e964..30787297 100644
--- a/src/java/com/juick/http/www/UserThread.java
+++ b/src/java/com/juick/http/www/UserThread.java
@@ -40,7 +40,6 @@ public class UserThread {
protected void doGetThread(Connection sql, HttpServletRequest request, HttpServletResponse response, com.juick.User user, int MID) throws ServletException, IOException {
com.juick.User visitor = Utils.getVisitorUser(sql, request);
Locale locale = request.getLocale();
- ResourceBundle rb = ResourceBundle.getBundle("User", locale);
boolean listview = false;
String paramView = request.getParameter("view");
@@ -69,24 +68,9 @@ public class UserThread {
out.println("<div id=\"wrapper\">");
out.println("<div id=\"content\" style=\"margin-left: 0; width: 100%\">");
- out.println("<ul>");
printMessage(out, sql, MID, locale);
- out.println("</ul>");
-
- out.println("<div class=\"title2\">");
- out.print(" <div class=\"title2-right\">");
- if (listview) {
- out.print("<a href=\"?view=tree\">" + rb.getString("View as tree") + "</a>");
- } else {
- out.print("<a href=\"#\" onclick=\"$('#replies>li').show(); $('#replies .msg-comments').hide(); return false\">" + rb.getString("Expand all") + "</a> &#183; <a href=\"?view=list\">" + rb.getString("View as list") + "</a>");
- }
- out.print("</div>");
- out.println(" <h2>Replies</h2>");
- out.println("</div>");
- out.println("<ul id=\"replies\">");
printReplies(out, sql, MID, locale, listview);
- out.println("</ul>");
out.println("<script type=\"text/javascript\">");
out.println("$(\"textarea\").autoResize();");
@@ -96,7 +80,7 @@ public class UserThread {
out.println("</div>");
- PageTemplates.pageFooter(out, locale);
+ PageTemplates.pageFooter(request, out, locale, visitor);
} finally {
out.close();
}
@@ -143,11 +127,12 @@ public class UserThread {
txt = PageTemplates.formatMessage(txt);
- out.println(" <li class=\"msg\" style=\"border: 0\">");
+ out.println("<ul>");
+ out.println(" <li id=\"msg-" + mid + "\" class=\"msg\" style=\"border: 0\">");
if (rs.getString(11) != null) {
if (rs.getString(11).equals("jpg")) {
- out.println(" <div class=\"msg-media\"><img src=\"http://i.juick.com/photos-512/" + mid + ".jpg\" alt=\"\"/></div>");
+ out.println(" <div class=\"msg-media\"><a href=\"http://i.juick.com/photos-1024/" + mid + ".jpg\"><img src=\"http://i.juick.com/photos-512/" + mid + ".jpg\" alt=\"\"/></a></div>");
} else {
out.println(" <div class=\"msg-media\"><div id=\"video-" + mid + "\"><b>Attachment: <a href=\"http://i.juick.com/video/" + mid + ".mp4\">Video</a></b></div></div>");
out.println(" <script type=\"text/javascript\">");
@@ -162,7 +147,13 @@ public class UserThread {
out.println(" </ul></div></div>");
out.println(" <div class=\"msg-header\"><a href=\"/" + uname + "/\">@" + uname + "</a>:" + tags + "</div>");
out.println(" <div class=\"msg-txt\">" + txt + "</div>");
+
+ out.println(" <form action=\"/post\" method=\"POST\" enctype=\"multipart/form-data\"><input type=\"hidden\" name=\"mid\" value=\"" + mid + "\"/>");
+ out.println(" <div class=\"msg-comment\"><textarea name=\"body\" rows=\"1\" placeholder=\"Add a comment...\" onkeypress=\"postformListener(this.form,event)\"></textarea></div>");
+ out.println(" </form>");
+
out.println(" </li>");
+ out.println("</ul>");
}
} catch (SQLException e) {
System.err.println(e);
@@ -173,6 +164,7 @@ public class UserThread {
}
public static void printReplies(PrintWriter out, Connection sql, int mid, Locale locale, boolean listview) {
+ ResourceBundle rbuser = ResourceBundle.getBundle("User", locale);
ArrayList<com.juick.Message> replies = new ArrayList<com.juick.Message>();
PreparedStatement stmt = null;
@@ -217,10 +209,26 @@ public class UserThread {
Utils.finishSQL(rs, stmt);
}
- if (listview) {
- printList(out, replies, locale);
- } else {
- printTree(out, replies, 0, 0, locale);
+ if (!replies.isEmpty()) {
+
+ out.println("<div class=\"title2\">");
+ out.print(" <div class=\"title2-right\">");
+ if (listview) {
+ out.print("<a href=\"?view=tree\">" + rbuser.getString("View as tree") + "</a>");
+ } else {
+ out.print("<a href=\"#\" onclick=\"$('#replies>li').show(); $('#replies .msg-comments').hide(); return false\">" + rbuser.getString("Expand all") + "</a> &#183; <a href=\"?view=list\">" + rbuser.getString("View as list") + "</a>");
+ }
+ out.print("</div>");
+ out.println(" <h2>Replies (" + replies.size() + ")</h2>");
+ out.println("</div>");
+
+ out.println("<ul id=\"replies\">");
+ if (listview) {
+ printList(out, replies, locale);
+ } else {
+ printTree(out, replies, 0, 0, locale);
+ }
+ out.println("</ul>");
}
for (int i = 0; i < replies.size(); i++) {
@@ -230,6 +238,8 @@ public class UserThread {
}
public static void printTree(PrintWriter out, ArrayList<com.juick.Message> replies, int ReplyTo, int margin, Locale locale) {
+ ResourceBundle rb = ResourceBundle.getBundle("Global", locale);
+
for (int i = 0; i < replies.size(); i++) {
com.juick.Message msg = replies.get(i);
if (msg.ReplyTo == ReplyTo) {
@@ -258,6 +268,8 @@ public class UserThread {
out.println(" </ul></div></div>");
out.println(" <div class=\"msg-header\"><a href=\"/" + msg.User.UName + "/\">@" + msg.User.UName + "</a>:</div>");
out.println(" <div class=\"msg-txt\">" + msg.Text + "</div>");
+ out.println(" <div class=\"msg-links\"><a href=\"#\" onclick=\"return showCommentFormComment(" + msg.MID + "," + msg.RID + ")\">" + rb.getString("Comment") + "</a></div>");
+ out.println(" <div class=\"msg-comment\" style=\"display: none\"></div>");
if (ReplyTo == 0) {
int childs = msg.getChildsCount() - 1;
if (childs > 0) {
@@ -272,6 +284,8 @@ public class UserThread {
}
public static void printList(PrintWriter out, ArrayList<com.juick.Message> replies, Locale locale) {
+ ResourceBundle rb = ResourceBundle.getBundle("Global", locale);
+
for (int i = 0; i < replies.size(); i++) {
com.juick.Message msg = replies.get(i);
@@ -292,6 +306,8 @@ public class UserThread {
out.println(" </ul></div></div>");
out.println(" <div class=\"msg-header\"><a href=\"/" + msg.User.UName + "/\">@" + msg.User.UName + "</a>:</div>");
out.println(" <div class=\"msg-txt\">" + msg.Text + "</div>");
+ out.println(" <div class=\"msg-links\"><a href=\"#\" onclick=\"return showCommentFormComment(" + msg.MID + "," + msg.RID + ")\">" + rb.getString("Comment") + "</a></div>");
+ out.println(" <div class=\"msg-comment\" style=\"display: none\"></div>");
out.println(" </li>");
}
}
diff --git a/src/java/com/juick/http/www/Utils.java b/src/java/com/juick/http/www/Utils.java
index cfa4484d..80577d04 100644
--- a/src/java/com/juick/http/www/Utils.java
+++ b/src/java/com/juick/http/www/Utils.java
@@ -101,6 +101,8 @@ public class Utils {
String ret = str;
ret = ret.replaceAll("<", "&lt;");
ret = ret.replaceAll(">", "&gt;");
+ ret = ret.replaceAll("'", "&apos;");
+ ret = ret.replaceAll("\"", "&quot;");
return str;
}
diff --git a/src/java/ru/sape/Sape.java b/src/java/ru/sape/Sape.java
new file mode 100644
index 00000000..c00054ae
--- /dev/null
+++ b/src/java/ru/sape/Sape.java
@@ -0,0 +1,25 @@
+/*
+ * http://code.google.com/p/javasape/
+ */
+package ru.sape;
+
+import javax.servlet.http.Cookie;
+
+public class Sape {
+
+ private final String sapeUser;
+ private final SapeConnection sapePageLinkConnection;
+
+ public Sape(String sapeUser, String host, int socketTimeout, int cacheLifeTime) {
+ this.sapeUser = sapeUser;
+
+ this.sapePageLinkConnection = new SapeConnection(
+ "/code.php?user=" + sapeUser + "&host=" + host,
+ "SAPE_Client PHP", socketTimeout, cacheLifeTime);
+ }
+ public boolean debug = false;
+
+ public SapePageLinks getPageLinks(String requestUri, Cookie[] cookies) {
+ return new SapePageLinks(sapePageLinkConnection, sapeUser, requestUri, cookies, debug);
+ }
+}
diff --git a/src/java/ru/sape/SapeConnection.java b/src/java/ru/sape/SapeConnection.java
new file mode 100644
index 00000000..8c794b08
--- /dev/null
+++ b/src/java/ru/sape/SapeConnection.java
@@ -0,0 +1,107 @@
+package ru.sape;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class SapeConnection {
+
+ private final String version = "1.0.3";
+ private final List<String> serverList = Arrays.asList("dispenser-01.sape.ru", "dispenser-02.sape.ru");
+ private final String dispenserPath;
+ private final String userAgent;
+ private final int socketTimeout;
+ private final int cacheLifeTime;
+
+ public SapeConnection(String dispenserPath, String userAgent, int socketTimeout, int cacheLifeTime) {
+ this.dispenserPath = dispenserPath;
+ this.userAgent = userAgent;
+ this.socketTimeout = socketTimeout;
+ this.cacheLifeTime = cacheLifeTime;
+ }
+
+ protected String fetchRemoteFile(String host, String path) throws IOException {
+ Reader r = null;
+
+ try {
+ HttpURLConnection connection = (HttpURLConnection) ((new URL(("http://" + host + path)).openConnection()));
+
+ if (socketTimeout > 0) {
+ connection.setConnectTimeout(socketTimeout);
+ connection.setReadTimeout(socketTimeout);
+ }
+
+ connection.addRequestProperty("User-Agent", userAgent + ' ' + version);
+
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+ connection.setRequestMethod("GET");
+ connection.connect();
+
+ r = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
+
+ StringWriter sw = new StringWriter();
+
+ int b;
+
+ while ((b = r.read()) != -1) {
+ sw.write(b);
+ }
+
+ return sw.toString();
+ } finally {
+ if (r != null) {
+ r.close();
+ }
+ }
+ }
+ Map<String, Object> cached;
+ long cacheUpdated;
+
+ @SuppressWarnings("unchecked")
+ public Map<String, Object> getData() {
+ if (cacheLifeTime <= (System.currentTimeMillis() - cacheUpdated) / 1000) {
+ for (String server : serverList) {
+ String data;
+
+ try {
+ data = fetchRemoteFile(server, dispenserPath + "&charset=UTF-8");
+ } catch (IOException e1) {
+ continue;
+ }
+
+ if (data.startsWith("FATAL ERROR:")) {
+ System.err.println("Sape responded with error: " + data);
+
+ continue;
+ }
+
+ try {
+ cached = (Map<String, Object>) new SerializedPhpParser(data).parse();
+ } catch (Exception e) {
+ System.err.println("Can't parse Sape data: " + e);
+ continue;
+ }
+
+ cacheUpdated = System.currentTimeMillis();
+
+ return cached;
+ }
+
+ System.err.println("Unable to fetch Sape data");
+
+ return new HashMap<String, Object>();
+ }
+
+ return cached;
+ }
+}
diff --git a/src/java/ru/sape/SapePageLinks.java b/src/java/ru/sape/SapePageLinks.java
new file mode 100644
index 00000000..498aeac0
--- /dev/null
+++ b/src/java/ru/sape/SapePageLinks.java
@@ -0,0 +1,95 @@
+package ru.sape;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.Cookie;
+
+public class SapePageLinks {
+
+ private boolean showCode;
+
+ public SapePageLinks(SapeConnection sapeConnection, String sapeUser, String requestUri, Cookie[] cookies) {
+ this(sapeConnection, sapeUser, requestUri, cookies, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ public SapePageLinks(SapeConnection sapeConnection, String sapeUser, String requestUri, Cookie[] cookies, boolean showCode) {
+ if (sapeUser.equals(getCookieValue(cookies, "sape_cookie"))) {
+ showCode = true;
+ }
+
+ Map<String, Object> data = sapeConnection.getData();
+
+ if (data.containsKey("__sape_delimiter__")) {
+ linkDelimiter = (String) data.get("__sape_delimiter__");
+ }
+
+ if (data.containsKey(requestUri)) {
+ pageLinks = new ArrayList<String>(((Map<Object, String>) data.get(requestUri)).values());
+ }
+
+ if (data.containsKey("__sape_new_url__")) {
+ if (showCode) {
+ Object newUrl = data.get("__sape_new_url__");
+
+ if (newUrl instanceof Map) {
+ pageLinks = new ArrayList<String>(((Map<Object, String>) newUrl).values());
+ } else {
+ pageLinks = new ArrayList<String>(Arrays.asList((String) newUrl));
+ }
+ }
+ }
+
+ this.showCode = showCode;
+ }
+ private String linkDelimiter = ".";
+ private List<String> pageLinks = new ArrayList<String>();
+
+ public String render() {
+ return render(-1);
+ }
+
+ public String render(int count) {
+ StringBuilder s = new StringBuilder();
+
+ if (count < 0) {
+ count = pageLinks.size();
+ }
+
+ for (Iterator<String> i = pageLinks.iterator(); i.hasNext() && count > 0; count--) {
+ if (s.length() > 0) {
+ s.append(linkDelimiter);
+ }
+
+ String l = i.next();
+
+ s.append(l);
+
+ i.remove();
+ }
+
+ if (showCode) {
+ s.insert(0, "<sape_noindex>");
+ s.append("</sape_noindex>");
+ }
+
+ return s.toString();
+ }
+
+ private static String getCookieValue(Cookie[] cookies, String name) {
+ if (cookies == null) {
+ return null;
+ }
+
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals(name)) {
+ return cookie.getValue();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/java/ru/sape/SerializedPhpParser.java b/src/java/ru/sape/SerializedPhpParser.java
new file mode 100644
index 00000000..a24551b9
--- /dev/null
+++ b/src/java/ru/sape/SerializedPhpParser.java
@@ -0,0 +1,221 @@
+/*
+Copyright (c) 2007 Zsolt Szász <zsolt at lorecraft dot com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package ru.sape;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * Deserializes a serialized PHP data structure into corresponding Java objects. It supports
+ * the integer, float, boolean, string primitives that are mapped to their Java
+ * equivalent, plus arrays that are parsed into <code>Map</code> instances and objects
+ * that are represented by {@link SerializedPhpParser.PhpObject} instances.
+ * <p>
+ * Example of use:
+ * <pre>
+ * String input = "O:8:"TypeName":1:{s:3:"foo";s:3:"bar";}";
+ * SerializedPhpParser serializedPhpParser = new SerializedPhpParser(input);
+ * Object result = serializedPhpParser.parse();
+ * </pre>
+ *
+ * The <code>result</code> object will be a <code>PhpObject</code> with the name "TypeName" and
+ * the attribute "foo" = "bar".
+ */
+class SerializedPhpParser {
+
+ private final String input;
+ private int index;
+ private boolean assumeUTF8 = true;
+ private Pattern acceptedAttributeNameRegex = null;
+
+ public SerializedPhpParser(String input) {
+ this.input = input;
+ }
+
+ public Object parse() {
+ char type = input.charAt(index);
+ switch (type) {
+ case 'i':
+ index += 2;
+ return parseInt();
+ case 'd':
+ index += 2;
+ return parseFloat();
+ case 'b':
+ index += 2;
+ return parseBoolean();
+ case 's':
+ index += 2;
+ return parseString();
+ case 'a':
+ index += 2;
+ return parseArray();
+ case 'O':
+ index += 2;
+ return parseObject();
+ case 'N':
+ index += 2;
+ return NULL;
+ default:
+ throw new IllegalStateException("Encountered unknown type [" + type + "], str=" + input.substring(index));
+ }
+ }
+
+ private Object parseObject() {
+ PhpObject phpObject = new PhpObject();
+ int strLen = readLength();
+ phpObject.name = input.substring(index, index + strLen);
+ index = index + strLen + 2;
+ int attrLen = readLength();
+ for (int i = 0; i < attrLen; i++) {
+ Object key = parse();
+ Object value = parse();
+ if (isAcceptedAttribute(key)) {
+ phpObject.attributes.put(key, value);
+ }
+ }
+ index++;
+ return phpObject;
+ }
+
+ private Map<Object, Object> parseArray() {
+ int arrayLen = readLength();
+ Map<Object, Object> result = new LinkedHashMap<Object, Object>();
+ for (int i = 0; i < arrayLen; i++) {
+ Object key = parse();
+ Object value = parse();
+ if (isAcceptedAttribute(key)) {
+ result.put(key, value);
+ }
+ }
+ index++;
+ return result;
+ }
+
+ private boolean isAcceptedAttribute(Object key) {
+ if (acceptedAttributeNameRegex == null) {
+ return true;
+ }
+ if (!(key instanceof String)) {
+ return true;
+ }
+ return acceptedAttributeNameRegex.matcher((String) key).matches();
+ }
+
+ private int readLength() {
+ int delimiter = input.indexOf(':', index);
+ int arrayLen = Integer.valueOf(input.substring(index, delimiter));
+ index = delimiter + 2;
+ return arrayLen;
+ }
+
+ /**
+ * Assumes strings are utf8 encoded
+ *
+ * @return
+ */
+ private String parseString() {
+ int strLen = readLength();
+
+ int utfStrLen = 0;
+ int byteCount = 0;
+ while (byteCount != strLen) {
+ char ch = input.charAt(index + utfStrLen++);
+
+ /*
+ if (ch == '\'') {
+ utfStrLen -= 1;
+ break;
+ }
+ */
+
+ if (assumeUTF8) {
+ if ((ch >= 0x0001) && (ch <= 0x007F)) {
+ byteCount++;
+ } else if (ch > 0x07FF) {
+ byteCount += 3;
+ } else {
+ byteCount += 2;
+ }
+ } else {
+ byteCount++;
+ }
+ }
+ String value = input.substring(index, index + utfStrLen);
+ index = index + utfStrLen + 2;
+ return value;
+ }
+
+ private Boolean parseBoolean() {
+ int delimiter = input.indexOf(';', index);
+ String value = input.substring(index, delimiter);
+ if (value.equals("1")) {
+ value = "true";
+ } else if (value.equals("0")) {
+ value = "false";
+ }
+ index = delimiter + 1;
+ return Boolean.valueOf(value);
+ }
+
+ private Double parseFloat() {
+ int delimiter = input.indexOf(';', index);
+ String value = input.substring(index, delimiter);
+ index = delimiter + 1;
+ return Double.valueOf(value);
+ }
+
+ private Integer parseInt() {
+ int delimiter = input.indexOf(';', index);
+ String value = input.substring(index, delimiter);
+ index = delimiter + 1;
+ return Integer.valueOf(value);
+ }
+
+ public void setAcceptedAttributeNameRegex(String acceptedAttributeNameRegex) {
+ this.acceptedAttributeNameRegex = Pattern.compile(acceptedAttributeNameRegex);
+ }
+ public static final Object NULL = new Object() {
+
+ @Override
+ public String toString() {
+ return "NULL";
+ }
+ };
+
+ /**
+ * Represents an object that has a name and a map of attributes
+ */
+ public static class PhpObject {
+
+ public String name;
+ public Map<Object, Object> attributes = new HashMap<Object, Object>();
+
+ @Override
+ public String toString() {
+ return "\"" + name + "\" : " + attributes.toString();
+ }
+ }
+}