diff --git a/apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java b/apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java new file mode 100644 index 000000000..293edf0ff --- /dev/null +++ b/apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java @@ -0,0 +1,292 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2003 Jive Software. All rights reserved. + * + * This software is the proprietary information of Jive Software. Use is subject to license terms. + */ + +package org.jivesoftware.webchat; + +/** + * A Filter that converts ASCII emoticons into image equivalents. + * This filter should only be run after any HTML stripping filters.

+ * + * The filter must be configured with information about where the image files + * are located. A table containing all the supported emoticons with their + * ASCII representations and image file names is as follows:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
EmotionASCIIImage
Happy:) or :-)happy.gif
Sad:( or :-(sad.gif
Grin:Dgrin.gif
Love:xlove.gif
Mischief;\mischief.gif
CoolB-)cool.gif
Devil]:)devil.gif
Silly:psilly.gif
AngryX-(angry.gif
Laugh:^Olaugh.gif
Wink;) or ;-)wink.gif
Blush:8}blush.gif
Cry:_|cry.gif
Confused?:|confused.gif
Shocked:Oshocked.gif
Plain:|plain.gif
+ * + * Note: special thanks to August Harrison for implementing an earlier version of this filter. + */ +public class EmoticonFilter { + + private static String imageHappy = "happy.gif"; + private static String imageSad = "sad.gif"; + private static String imageGrin = "grin.gif"; + private static String imageLove = "love.gif"; + private static String imageMischief = "mischief.gif"; + private static String imageCool = "cool.gif"; + private static String imageDevil = "devil.gif"; + private static String imageSilly = "silly.gif"; + private static String imageAngry = "angry.gif"; + private static String imageLaugh = "laugh.gif"; + private static String imageWink = "wink.gif"; + private static String imageBlush = "blush.gif"; + private static String imageCry = "cry.gif"; + private static String imageConfused = "confused.gif"; + private static String imageShocked = "shocked.gif"; + private static String imagePlain = "plain.gif"; + private static String imageURL = "images/emoticons"; + + // Placeholders for the built image tags + private static String imgHappy; + private static String imgSad; + private static String imgGrin; + private static String imgLove; + private static String imgMischief; + private static String imgCool; + private static String imgDevil; + private static String imgSilly; + private static String imgAngry; + private static String imgLaugh; + private static String imgWink; + private static String imgBlush; + private static String imgCry; + private static String imgConfused; + private static String imgShocked; + private static String imgPlain; + + public EmoticonFilter() { + buildImageTags(); + } + + public String applyFilter(String string) { + if (string == null || string.length() < 1) { + return string; + } + + int length = string.length(); + StringBuffer filtered = new StringBuffer(string.length() + 100); + char[] chars = string.toCharArray(); + + int length1 = length - 1; + int length2 = length - 2; + + int index = -1, i = 0, oldend = 0; + String imgTag; + + // Replace each of the emoticons, expanded search for performance + while (++index < length1) { + // no tag found yet... + imgTag = null; + + switch (chars[i = index]) { + case ']': + // "]:)" + if (i < length2 && chars[++i] == ':' && chars[++i] == ')') { + imgTag = imgDevil; + } + break; + case ':': + switch (chars[++i]) { + case ')': + // ":)" + imgTag = imgHappy; + break; + case '-': + // ":-)" + if (i < length1 && chars[++i] == ')') { + imgTag = imgHappy; + } + // ":-(" + else if (chars[i] == '(') { + imgTag = imgSad; + } + break; + case '(': + // ":(" + imgTag = imgSad; + break; + case 'D': + // ":D" + imgTag = imgGrin; + break; + case 'x': + // ":x" + imgTag = imgLove; + break; + case 'p': + // ":p" + imgTag = imgSilly; + break; + case '^': + // ":^O" + if (i < length1 && chars[++i] == 'O') { + imgTag = imgLaugh; + } + break; + case '8': + // ":8}" + if (i < length1 && chars[++i] == '}') { + imgTag = imgBlush; + } + break; + case '_': + // ":_|" + if (i < length1 && chars[++i] == '|') { + imgTag = imgCry; + } + break; + case 'O': + // ":O" + imgTag = imgShocked; + break; + case '|': + // ":|" + imgTag = imgPlain; + break; + default: + break; + } + break; + case ';': + switch (chars[++i]) { + case ')': + // ";)" + imgTag = imgWink; + break; + case '-': + // ";-)" + if (i < length1 && chars[++i] == ')') { + imgTag = imgWink; + } + break; + case '\\': + // ";\\" + imgTag = imgMischief; + break; + default: + break; + } + break; + case 'B': + // "B-)" + if (i < length2 && chars[++i] == '-' && chars[++i] == ')') { + imgTag = imgCool; + } + break; + case 'X': + // "X-(" + if (i < length2 && chars[++i] == '-' && chars[++i] == '(') { + imgTag = imgAngry; + } + break; + case '?': + // "?:|" + if (i < length2 && chars[++i] == ':' && chars[++i] == '|') { + imgTag = imgConfused; + } + break; + default: + break; + } + + // if we found one, replace + if (imgTag != null) { + filtered.append(chars, oldend, index-oldend); + filtered.append(imgTag); + + oldend = i + 1; + index = i; + } + } + + if (oldend < length) { + filtered.append(chars, oldend, length-oldend); + } + + return filtered.toString(); + } + + /** + * Returns the base URL for emoticon images. This can be specified as + * an absolute or relative path. + * + * @return the base URL for smiley images. + */ + public String getImageURL() { + return imageURL; + } + + /** + * Sets the base URL for emoticon images. This can be specified as + * an absolute or relative path. + * + * @param imageURL the base URL for emoticon images. + */ + public void setImageURL(String imageURL) { + if (imageURL != null && imageURL.length() > 0) { + if (imageURL.charAt(imageURL.length()-1) == '/') { + imageURL = imageURL.substring(0, imageURL.length()-1); + } + } + this.imageURL = imageURL; + + // rebuild the image tags + buildImageTags(); + } + + /** + * Build image tags + */ + private void buildImageTags() { + imgHappy = buildURL(imageHappy); + imgSad = buildURL(imageSad); + imgGrin = buildURL(imageGrin); + imgLove = buildURL(imageLove); + imgMischief = buildURL(imageMischief); + imgCool = buildURL(imageCool); + imgDevil = buildURL(imageDevil); + imgSilly = buildURL(imageSilly); + imgAngry = buildURL(imageAngry); + imgLaugh = buildURL(imageLaugh); + imgWink = buildURL(imageWink); + imgBlush = buildURL(imageBlush); + imgCry = buildURL(imageCry); + imgConfused = buildURL(imageConfused); + imgShocked = buildURL(imageShocked); + imgPlain = buildURL(imagePlain); + } + + /** + * Returns an HTML image tag using the base image URL and image name. + */ + private String buildURL(String imageName) { + String tag = ""; + + return tag; + } +} \ No newline at end of file diff --git a/apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java b/apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java new file mode 100644 index 000000000..de2f972b5 --- /dev/null +++ b/apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java @@ -0,0 +1,312 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 1999-2002 CoolServlets, Inc. All rights reserved. + * + * This software is the proprietary information of CoolServlets, Inc. + * Use is subject to license terms. + */ + +package org.jivesoftware.webchat; + +import java.util.*; + +/** + * A Filter that converts URL's to working HTML web links.

+ * + * The default set of patterns recognized are ftp://path-of-url, + * http://path-of-url, https://path-of-url but can be expanded upon.

+ * + * In addition, the following patterns are also recognized. + * + * [url path-of-url]descriptive text[/url] and + * [url=path-of-url]descriptive text[/url].

+ * + * The [url] allows any path to be defined as link. + */ +public class URLFilter{ + + private ArrayList schemes = new ArrayList(); + + // define a preset default set of schemes + public URLFilter() { + schemes.add("http://"); + schemes.add("https://"); + schemes.add("ftp://"); + } + + public String applyFilter(String string) { + if (string == null || string.length() == 0) { + return string; + } + + int length = string.length(); + StringBuffer filtered = new StringBuffer((int) (length * 1.5)); + ArrayList urlBlocks = new ArrayList(5); + + // search for url's such as [url=..]text[/url] or [url ..]text[/url] + int start = string.indexOf("[url"); + while (start != -1 && (start + 5 < length)) { + // check to verify we're not in another block + if (withinAnotherBlock(urlBlocks, start)) { + start = string.indexOf("[url", start + 5); + continue; + } + + int end = string.indexOf("[/url]", start + 5); + + if (end == -1 || end >= length) { + // went past end of string, skip + break; + } + + String u = string.substring(start, end + 6); + int startTagClose = u.indexOf(']'); + String url; + String description; + if (startTagClose > 5) { + url = u.substring(5, startTagClose); + description = u.substring(startTagClose + 1, u.length() - 6); + + // Check the user entered URL for a "javascript:" or "file:" link. Only + // append the user entered link if it doesn't contain 'javascript:' and 'file:' + String lcURL = url.toLowerCase(); + if (lcURL.indexOf("javascript:") == -1 && lcURL.indexOf("file:") == -1) { + URLBlock block = new URLBlock(start, end + 5, url, description); + urlBlocks.add(block); + } + } + else { + url = description = u.substring(startTagClose + 1, u.length() - 6); + // Check the user entered URL for a "javascript:" or "file:" link. Only + // append the user entered link if it doesn't contain 'javascript:' and 'file:' + String lcURL = url.toLowerCase(); + if (lcURL.indexOf("javascript:") == -1 && lcURL.indexOf("file:") == -1) { + URLBlock block = new URLBlock(start, end + 5, url); + urlBlocks.add(block); + } + } + + start = string.indexOf("[url", end + 6); + } + + // now handle all the other urls + Iterator iter = schemes.iterator(); + + while (iter.hasNext()) { + String scheme = (String) iter.next(); + start = string.indexOf(scheme, 0); + + while (start != -1) { + int end = start; + + // check context, don't handle patterns preceded by any of '"<= + if (start > 0) { + char c = string.charAt(start - 1); + + if (c == '\'' || c == '"' || c == '<' || c == '=') { + start = string.indexOf(scheme, start + scheme.length()); + continue; + } + } + + // check to verify we're not in another block + if (withinAnotherBlock(urlBlocks, start)) { + start = string.indexOf(scheme, start + scheme.length()); + continue; + } + + // find the end of the url + int cur = start + scheme.length(); + while (end == start && cur < length) { + char c = string.charAt(cur); + + switch (c) { + case ' ': + end = cur; + break; + case '\t': + end = cur; + break; + case '\'': + end = cur; + break; + case '\"': + end = cur; + break; + case '<': + end = cur; + break; + case '[': + end = cur; + break; + case '\n': + end = cur; + break; + case '\r': + end = cur; + break; + default: + // acceptable character + } + + cur++; + } + + // if this is true it means the url goes to the end of the string + if (end == start) { + end = length - 1; + } + + URLBlock block = new URLBlock(start, end-1, string.substring(start, end)); + urlBlocks.add(block); + + start = string.indexOf(scheme, end); + } + } + + // sort the blocks so that they are in start index order + sortBlocks(urlBlocks); + + // now, markup the urls and pass along the filter chain the rest + Iterator blocks = urlBlocks.iterator(); + int last = 0; + + while (blocks.hasNext()) { + URLBlock block = (URLBlock) blocks.next(); + + if (block.getStart() > 0) { + filtered.append(string.substring(last, block.getStart())); + } + + last = block.getEnd() + 1; + + filtered.append(""); + if (block.getDescription().length() > 0) { + filtered.append(block.getDescription()); + } + else { + filtered.append(block.getUrl()); + } + filtered.append(""); + } + + if (last < string.length() - 1) { + filtered.append(string.substring(last)); + } + + return filtered.toString(); + } + + /** + * Returns the current supported uri schemes as a comma seperated string. + * + * @return the current supported uri schemes as a comma seperated string. + */ + public String getSchemes() { + StringBuffer buf = new StringBuffer(50); + + for (int i = 0; i < schemes.size(); i++) { + buf.append((String) schemes.get(i)).append(","); + } + buf.deleteCharAt(buf.length() - 1); + + return buf.toString(); + } + + /** + * Sets the current supported uri schemes as a comma seperated string. + * + * @param schemes a comma seperated string of uri schemes. + */ + public void setSchemes(String schemes) { + if (schemes == null) { + return; + } + + // enpty the current list + this.schemes.clear(); + + StringTokenizer st = new StringTokenizer(schemes, ","); + + while (st.hasMoreElements()) { + this.schemes.add(st.nextElement()); + } + } + + private void sortBlocks(ArrayList blocks) { + Collections.sort(blocks, new Comparator() { + public int compare(Object object1, Object object2) { + URLBlock b1 = (URLBlock) object1; + URLBlock b2 = (URLBlock) object2; + return (b1.getStart() > b2.getStart()) ? 1 : -1; + } + }); + } + + private boolean withinAnotherBlock(List blocks, int start) { + for (int i = 0; i < blocks.size(); i++) { + URLBlock block = (URLBlock) blocks.get(i); + + if (start >= block.getStart() && start < block.getEnd()) { + return true; + } + } + + return false; + } + + class URLBlock { + int start = 0; + int end = 0; + String description = ""; + String url = ""; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + URLBlock(int start, int end, String url) { + this.start = start; + this.end = end; + this.url = url; + } + + URLBlock(int start, int end, String url, String description) { + this.start = start; + this.end = end; + this.description = description; + this.url = url; + } + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } + } +} \ No newline at end of file diff --git a/apps/webchat/source/web/images/emoticons/angry.gif b/apps/webchat/source/web/images/emoticons/angry.gif new file mode 100644 index 000000000..6489c9bc9 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/angry.gif differ diff --git a/apps/webchat/source/web/images/emoticons/blush.gif b/apps/webchat/source/web/images/emoticons/blush.gif new file mode 100644 index 000000000..22f1db550 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/blush.gif differ diff --git a/apps/webchat/source/web/images/emoticons/confused.gif b/apps/webchat/source/web/images/emoticons/confused.gif new file mode 100644 index 000000000..ef1107bec Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/confused.gif differ diff --git a/apps/webchat/source/web/images/emoticons/cool.gif b/apps/webchat/source/web/images/emoticons/cool.gif new file mode 100644 index 000000000..2d805e5da Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/cool.gif differ diff --git a/apps/webchat/source/web/images/emoticons/cry.gif b/apps/webchat/source/web/images/emoticons/cry.gif new file mode 100644 index 000000000..e244944c8 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/cry.gif differ diff --git a/apps/webchat/source/web/images/emoticons/devil.gif b/apps/webchat/source/web/images/emoticons/devil.gif new file mode 100644 index 000000000..31bca49fb Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/devil.gif differ diff --git a/apps/webchat/source/web/images/emoticons/grin.gif b/apps/webchat/source/web/images/emoticons/grin.gif new file mode 100644 index 000000000..e5c92e2d5 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/grin.gif differ diff --git a/apps/webchat/source/web/images/emoticons/happy.gif b/apps/webchat/source/web/images/emoticons/happy.gif new file mode 100644 index 000000000..20a93e32b Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/happy.gif differ diff --git a/apps/webchat/source/web/images/emoticons/laugh.gif b/apps/webchat/source/web/images/emoticons/laugh.gif new file mode 100644 index 000000000..e808a2583 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/laugh.gif differ diff --git a/apps/webchat/source/web/images/emoticons/love.gif b/apps/webchat/source/web/images/emoticons/love.gif new file mode 100644 index 000000000..d1c320e3d Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/love.gif differ diff --git a/apps/webchat/source/web/images/emoticons/mischief.gif b/apps/webchat/source/web/images/emoticons/mischief.gif new file mode 100644 index 000000000..238db06f3 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/mischief.gif differ diff --git a/apps/webchat/source/web/images/emoticons/plain.gif b/apps/webchat/source/web/images/emoticons/plain.gif new file mode 100644 index 000000000..a5beeea43 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/plain.gif differ diff --git a/apps/webchat/source/web/images/emoticons/sad.gif b/apps/webchat/source/web/images/emoticons/sad.gif new file mode 100644 index 000000000..0320885df Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/sad.gif differ diff --git a/apps/webchat/source/web/images/emoticons/shocked.gif b/apps/webchat/source/web/images/emoticons/shocked.gif new file mode 100644 index 000000000..20a70f8cd Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/shocked.gif differ diff --git a/apps/webchat/source/web/images/emoticons/silly.gif b/apps/webchat/source/web/images/emoticons/silly.gif new file mode 100644 index 000000000..a162605bd Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/silly.gif differ diff --git a/apps/webchat/source/web/images/emoticons/wink.gif b/apps/webchat/source/web/images/emoticons/wink.gif new file mode 100644 index 000000000..6d91b0fa2 Binary files /dev/null and b/apps/webchat/source/web/images/emoticons/wink.gif differ