1 10 11 package org.mmbase.applications.community.builders; 12 13 import org.mmbase.applications.community.modules.*; 14 import java.util.*; 15 import java.io.*; 16 17 import org.mmbase.module.core.*; 18 import org.mmbase.module.corebuilders.*; 19 import org.mmbase.util.*; 20 import org.mmbase.util.logging.*; 21 22 33 34 public class Message extends MMObjectBuilder { 35 36 public final static int POST_OK = 0; 38 public final static int POST_ERROR_UNKNOWN = -1; 39 public final static int POST_ERROR_BODY_EXCEEDS_SIZE = -2; 40 public final static int POST_ERROR_NO_USER = -3; 41 public final static int POST_ERROR_NEED_LOGIN = -4; 42 public final static int POST_ERROR_RELATION_CHANNEL = -5; 43 public final static int POST_ERROR_RELATION_USER = -6; 44 public final static int POST_ERROR_NO_BODY_TEXT = -7; 45 public final static int POST_ERROR_NO_SUBJECT = -8; 46 47 private static final Logger log = Logging.getLoggerInstance(Message.class); 49 50 51 public static final String LIST_HEAD_TAG = "<ul>"; 52 53 public static final String LIST_TAIL_TAG = "</ul>"; 54 55 56 public static final String F_THREAD = "thread"; 57 58 public static final String F_BODY = "body"; 59 60 public static final String F_SUBJECT = "subject"; 61 62 public static final String F_SEQUENCE = "sequence"; 63 64 public static final String F_INFO = "info"; 65 66 public static final String F_TIMESTAMP = "timestamp"; 67 68 public static final String F_TIMESTAMPSEC = "timestampsec"; 69 70 71 public static final String F_RE_SUBJECT = "resubject"; 72 73 public static final String F_REPLY_COUNT = "replycount"; 74 75 public static final String F_HAS_REPLIES = "hasreplies"; 76 77 public static final String F_PARENT = "parent"; 78 79 80 public static final String F_GET_INFO_VALUE = "getinfovalue"; 81 82 85 protected int maxBodySize = 2024; 86 private int expireTime = 1 * 60 * 1000; 88 89 private Channel channelBuilder; 90 91 public TemporaryNodeManager tmpNodeManager = null; 92 private String messageUser = null; 93 private int tmpNumbers = 0; 95 private final String tmpNumberPrefix = "cmt"; 96 97 private NodeBreaker chatboxMessages = null; 99 100 private boolean active = false; 102 103 106 public Message() { 107 } 108 109 public boolean init() { 110 boolean result = super.init(); 111 112 String maxBody = getInitParameter("maxbodysize"); 113 if ((maxBody != null) && (maxBody.length() > 0)) { 114 try { 115 maxBodySize = Integer.parseInt(maxBody); 116 } catch (Exception e) { 117 log.warn("Invalid value for property'maxbodysize' :" + maxBody); 118 } 119 } 120 121 messageUser = getInitParameter("postas"); 122 if ((messageUser == null) || (messageUser.length() == 0)) { 123 messageUser = "system"; 124 } 125 tmpNodeManager = new TemporaryNodeManager(mmb); 126 chatboxMessages = new NodeBreaker(2 * expireTime, tmpNodeManager); 128 129 checkAddTmpField("channel"); checkAddTmpField("user"); checkAddTmpField("username"); 138 activate(); 139 140 return result; 141 } 142 143 147 public boolean activate() { 148 if (!active) { 149 channelBuilder = (Channel) mmb.getMMObject("channel"); 150 active = channelBuilder != null; 151 } 152 return active; 153 } 154 155 private int getParentChildRole() { 157 return mmb.getRelDef().getNumberByName("parent/child"); 158 } 159 160 private int getCreatorRole() { 162 return mmb.getRelDef().getNumberByName("creator/subject"); 163 } 164 165 171 public String getMessageError(int error) { 172 switch (error) { 173 case POST_ERROR_BODY_EXCEEDS_SIZE: 174 return "Message body size exceeds " + maxBodySize + " bytes"; 175 case POST_ERROR_NO_USER: 176 return "User name or object needed"; 177 case POST_ERROR_NEED_LOGIN: 178 return "User needs to be logged on to post"; 179 case POST_ERROR_RELATION_CHANNEL: 180 return "Could not create temporary relations between message and channel."; 181 case POST_ERROR_RELATION_USER: 182 return "Could not create temporary relations between message and user."; 183 case POST_ERROR_NO_BODY_TEXT: 184 return "No message body text specified."; 185 case POST_ERROR_NO_SUBJECT: 186 return "No subject specified."; 187 default : 188 return "Could not post message."; 189 } 190 } 191 192 205 public int post(String subject, String body, int channel, int thread, int chatter, String chatterName) { 206 if (body.length() == 0) { 207 log.error("post(): no body text"); 208 return POST_ERROR_NO_BODY_TEXT; 209 } 210 if (subject.length() == 0) { 211 log.error("post(): no subject"); 212 return POST_ERROR_NO_SUBJECT; 213 } 214 if (body.length() > maxBodySize) { 215 log.error("post(): body size exceeds " + maxBodySize + " bytes"); 216 return POST_ERROR_BODY_EXCEEDS_SIZE; 217 } 218 219 if (chatterName != null) { 220 if (chatterName.length() == 0) { 221 log.error("post(): CHATTERNAME must be larger than 0 tokens"); 222 chatterName = null; 223 } 224 } 225 if ((chatterName == null) && (chatter == -1)) { 226 return POST_ERROR_NO_USER; 227 } 228 229 MMObjectNode channelNode = getNode(channel); 230 if ((channelNode.getIntValue(Channel.F_STATE) & Channel.STATE_WRITE_LOGIN) > 0) { 234 if (chatter == -1) { 235 return POST_ERROR_NEED_LOGIN; 236 } 237 } 238 239 MMObjectNode node = getNewNode(messageUser); 240 node.setValue(F_SUBJECT, subject); 241 node.setValue(F_BODY, body); 242 node.setValue(F_THREAD, thread); 243 244 node.setValue(F_SEQUENCE, channelBuilder.getNewSequence(channelNode)); 245 252 if (log.isDebugEnabled()) { 253 log.debug("post(): make relation message with thread and chatter"); 254 } 255 InsRel insrel = mmb.getInsRel(); 256 if (chatterName != null) { 257 setInfoField(node, "name", chatterName); 258 } 260 int id = insert(messageUser, node); 261 if (chatter > 0) { 262 MMObjectNode chattertomsg = insrel.getNewNode(messageUser); 263 chattertomsg.setValue("snumber", chatter); 264 chattertomsg.setValue("dnumber", id); 265 chattertomsg.setValue("rnumber", getCreatorRole()); 266 insrel.insert(messageUser, chattertomsg); 267 } 268 MMObjectNode msgtothread = insrel.getNewNode(messageUser); 269 msgtothread.setValue("snumber", id); 270 msgtothread.setValue("dnumber", thread); 271 msgtothread.setValue("rnumber", getParentChildRole()); 272 insrel.insert(messageUser, msgtothread); 273 insrel.deleteRelationCache(thread); 274 return id; 275 } 276 277 287 public int post(String body, int channel, int chatter) { 288 return post(body, channel, chatter, null); 289 } 290 291 300 public int post(String body, int channel, int chatter, String chatterName) { 301 if (body.length() == 0) { 302 return POST_ERROR_NO_BODY_TEXT; 303 } 304 if (body.length() > maxBodySize) { 305 return POST_ERROR_BODY_EXCEEDS_SIZE; 306 } 307 308 MMObjectNode channelNode = getNode(channel); 309 if ((channelNode.getIntValue(Channel.F_STATE) & Channel.STATE_WRITE_LOGIN) > 0) { 313 if (chatter == -1) 314 return POST_ERROR_NEED_LOGIN; 315 } 316 317 String key = tmpNodeManager.createTmpNode("message", messageUser, getNewTemporaryKey()); 319 MMObjectNode message = getNewTmpNode(messageUser, key); 320 321 int sequence = channelBuilder.getNewSequence(channelNode); 323 324 if (chatterName == null) { 325 chatterName = "unknown"; 326 if (chatter != -1) { 327 MMObjectNode chatternode = getNode(chatter); 328 if (chatternode != null) { 329 chatterName = chatternode.getStringValue("gui()"); 330 } else { 331 chatterName = "chatter_" + chatter; 332 } 333 } 334 } 335 336 message.setValue(F_BODY, body); 339 message.setValue(F_THREAD, channel); 340 message.setValue(F_SEQUENCE, sequence); 341 boolean useTimeStamp = (getField(F_TIMESTAMP) != null); 342 if (useTimeStamp) { 343 message.setValue(F_TIMESTAMP, System.currentTimeMillis()); 344 } else { 345 TimeStamp timeStamp = new TimeStamp(); 346 message.setValue("timestampl", timeStamp.lowIntegerValue()); 347 message.setValue("timestamph", timeStamp.highIntegerValue()); 348 } 349 setInfoField(message, "name", chatterName); 350 351 Writer recorder = channelBuilder.getRecorder(channel); 352 if (recorder != null) { 353 try { 354 recorder.write(chatterName + " : " + body + "\n"); 355 } catch (IOException e) { 356 log.error("" + e); 357 } 358 } 359 360 363 int result = POST_OK; 364 try { 365 String tmp = tmpNodeManager.createTmpRelationNode("parent", messageUser, getNewTemporaryKey(), "realchannel", key); 366 tmpNodeManager.setObjectField(messageUser, tmp, "snumber", new Integer (channel)); 367 chatboxMessages.add(messageUser + "_" + tmp, (new Long (System.currentTimeMillis() + expireTime)).longValue()); 369 } catch (Exception e) { 370 result = POST_ERROR_RELATION_CHANNEL; 371 } 372 if (chatter != -1) { 373 try { 374 String tmp = tmpNodeManager.createTmpRelationNode("creator", messageUser, getNewTemporaryKey(), "realuser", key); 375 tmpNodeManager.setObjectField(messageUser, tmp, "snumber", new Integer (chatter)); 376 chatboxMessages.add(messageUser + "_" + tmp, (new Long (System.currentTimeMillis() + expireTime)).longValue()); 378 MMObjectNode node = tmpNodeManager.getNode(messageUser, tmp); 379 if (log.isDebugEnabled()) { 380 log.debug("just set " + tmp + " snumber to " + node.getIntValue("snumber")); 381 } 382 } catch (Exception e) { 383 result = POST_ERROR_RELATION_USER; 384 } 385 } 386 chatboxMessages.add(messageUser + "_" + key, (new Long (System.currentTimeMillis() + expireTime)).longValue()); 388 return result; 389 } 390 391 397 public int insert(String owner, MMObjectNode node) { 398 400 boolean useTimeStamp = (getField(F_TIMESTAMP) != null); 401 if (useTimeStamp) { 402 node.setValue(F_TIMESTAMP, new Long (System.currentTimeMillis())); 403 } else { 404 TimeStamp timeStamp = new TimeStamp(); 405 node.setValue("timestampl", timeStamp.lowIntegerValue()); 406 node.setValue("timestamph", timeStamp.highIntegerValue()); 407 } 408 409 InsRel insrel = mmb.getInsRel(); 410 insrel.deleteRelationCache(node.getIntValue(F_THREAD)); 411 return (super.insert(owner, node)); 412 } 413 414 426 public int update(String chatterName, String subject, String body, int number) { 427 return update(chatterName, -1, subject, body, number); 428 } 429 430 443 public int update(String chatterName, int chatter, String subject, String body, int number) { 444 if (body.length() == 0) { 445 return POST_ERROR_NO_BODY_TEXT; 446 } 447 if (body.length() > maxBodySize) { 448 return POST_ERROR_BODY_EXCEEDS_SIZE; 449 } 450 451 MMObjectNode node = getNode(number); 452 Vector channels = node.getRelatedNodes("channel"); 453 if (channels.size() > 0) { 454 MMObjectNode channelNode = (MMObjectNode) channels.get(0); 455 if ((channelNode.getIntValue(Channel.F_STATE) & Channel.STATE_WRITE_LOGIN) > 0) { 459 if (chatter == -1) 460 return POST_ERROR_NEED_LOGIN; 461 } 462 } 463 log.info("Message:CHATTERNAME=" + chatterName); 464 if (chatterName != null) { 465 log.info("Message:Info pre=" + node.getStringValue("info")); 466 setInfoField(node, "name", chatterName); 467 log.info("Message:Info post=" + node.getStringValue("info")); 468 } 469 node.setValue(F_SUBJECT, subject); 470 node.setValue(F_BODY, body); 471 if (node.commit()) 472 return POST_OK; 473 else 474 return POST_ERROR_UNKNOWN; 475 } 476 477 510 public Vector getListMessages(StringTagger params) { 511 513 String id = params.Value("NODE"); 514 MMObjectNode node = getNode(id); 515 if (node == null) { 516 log.debug("getListMessages(): no or incorrect node specified"); 517 return new Vector(); 518 } 519 520 522 Vector fields = params.Values("FIELDS"); 523 524 530 String openTag = LIST_HEAD_TAG; 531 String closeTag = LIST_TAIL_TAG; 532 int listheadItemNr = fields.indexOf("listhead"); 533 int listtailItemNr = -1; 534 int depthItemNr = -1; 535 if (listheadItemNr >= 0) { 536 listtailItemNr = fields.indexOf("listtail"); 537 depthItemNr = fields.indexOf("depth"); 538 if (depthItemNr < 0) { 540 fields.add("depth"); 541 depthItemNr = fields.indexOf("depth"); 542 } 543 openTag = params.Value("OPENTAG"); 544 closeTag = params.Value("CLOSETAG"); 545 if ((openTag == null) || (closeTag == null)) { 546 openTag = LIST_HEAD_TAG; 547 closeTag = LIST_TAIL_TAG; 548 } else { 549 openTag = "<" + openTag.replace('\'', '"').replace('#', '=') + ">"; 550 closeTag = "</" + closeTag + ">"; 551 } 552 } 553 554 params.setValue("ITEMS", "" + fields.size()); 556 557 String tmp = params.Value("FROMCOUNT"); 559 int fromCount; 560 if (tmp != null) fromCount = Integer.decode(tmp).intValue(); else fromCount = 0; 561 int maxCount; 562 tmp = params.Value("MAXCOUNT"); 563 if (tmp == null) tmp = params.Value("maxCount"); 566 567 if (tmp != null) maxCount = Integer.decode(tmp).intValue(); else maxCount = Integer.MAX_VALUE; 568 int maxDepth; 569 tmp = params.Value("MAXDEPTH"); 570 if (tmp != null) maxDepth = Integer.decode(tmp).intValue(); else maxDepth = Integer.MAX_VALUE; 571 572 String nodeselectfield = "number"; 574 int startAfterNode = -1; 575 576 tmp = params.Value("STARTAFTERNODE"); 577 try { 578 if (tmp != null) { 579 startAfterNode = Integer.decode(tmp).intValue(); 580 } else { 581 tmp = params.Value("STARTAFTERSEQUENCE"); 582 if (tmp != null) { 583 startAfterNode = Integer.decode(tmp).intValue(); 584 nodeselectfield = F_SEQUENCE; 585 } 586 } 587 } catch (NumberFormatException e) { 588 log.error("" + e); 589 } 590 591 595 Vector sortFields = params.Values("SORTFIELDS"); 596 if (sortFields == null) { 597 sortFields = params.Values("DBSORT"); 598 if (sortFields == null) { 599 sortFields = new Vector(1); 600 sortFields.add(F_SEQUENCE); 601 } 602 } 603 Vector sortDirs = params.Values("SORTDIRS"); 604 if (sortDirs == null) sortDirs = params.Values("DBDIR"); 605 NodeComparator compareMessages; 606 if (sortDirs == null) { 607 compareMessages = new NodeComparator(sortFields); 608 } else { 609 compareMessages = new NodeComparator(sortFields, sortDirs); 610 } 611 612 Vector result = null; 613 614 if (maxCount == Integer.MAX_VALUE) { 615 result = getListMessages(node, fields, compareMessages, maxCount, 0, 617 maxDepth, startAfterNode, nodeselectfield); 618 } else { 619 result = getListMessages(node, fields, compareMessages, fromCount + maxCount, 0, 621 maxDepth, startAfterNode, nodeselectfield); 622 int realCount = (fromCount + maxCount) * fields.size(); 623 int realFromCount = (fromCount) * fields.size(); 624 if (result.size() > realCount) { 625 result = new Vector(result.subList(realFromCount, realCount)); 626 } else if (realFromCount > 0) { 627 if (realFromCount >= result.size()) { 628 result = new Vector(); 629 } else { 630 result = new Vector(result.subList(realFromCount, result.size())); 631 } 632 } 633 } 634 635 if ((listheadItemNr >= 0) && (listtailItemNr >= 0)) { 636 addListTags(result, listheadItemNr, listtailItemNr, depthItemNr, fields.size(), openTag, closeTag); 637 } else if ((listheadItemNr >= 0) || (listtailItemNr >= 0)) { 638 log.error("getListMessages(): Listhead and listtail only work when used together."); 639 } 640 return result; 641 } 642 643 660 public Vector getListMessages(MMObjectNode thread, Vector fields, Comparator ci, 661 int maxCount, int depth, int maxDepth, int startAfterNode, 662 String nodeselectfield) { 663 Vector result = new Vector(), childMsgs; 664 Vector relatedMessages = getRelatedMessages(thread, ci); 665 666 int msgPointer = relatedMessages.size() - 1; 667 int added = 0, count = 0; 668 String item, cmd; 669 MMObjectNode relmsg; 670 int fieldsCount = fields.size(); 671 int replycount; 672 boolean startAfterNodePassed = (startAfterNode == -1); 673 674 while ((msgPointer >= 0) && (added < maxCount)) { 675 relmsg = (MMObjectNode) relatedMessages.elementAt(msgPointer); 676 677 startAfterNodePassed = startAfterNodePassed || 678 (startAfterNode == relmsg.getIntValue(nodeselectfield)); 679 680 if (depth < maxDepth) { 681 childMsgs = getListMessages(relmsg, fields, ci, maxCount - added, depth + 1, 682 maxDepth, startAfterNode, nodeselectfield); 683 replycount = childMsgs.size() / fieldsCount; 684 added += replycount; 685 686 690 if (added == maxCount) replycount = getNrMsgAndHighSeq(relmsg).messageCount; 691 } else { 692 childMsgs = new Vector(); 693 replycount = getNrMsgAndHighSeq(relmsg).messageCount; 694 } 695 696 if (startAfterNodePassed) { 697 698 added++; 700 702 for (int i = 0; i < fieldsCount; i++) { 703 cmd = ((String ) fields.elementAt(i)).trim(); 704 if (cmd.equals("depth")) { 705 item = "" + depth; 706 } else if (cmd.equals("replycount")) { 707 item = "" + replycount; 708 } else if ((cmd.equals("listhead")) || 709 (cmd.equals("listtail"))) { 710 item = ""; 711 } else { 712 item = "" + relmsg.getValue(cmd); 713 } 714 result.add(item); 715 } 716 result.addAll(childMsgs); 717 } 718 msgPointer--; 719 count++; 720 } 721 return result; 722 } 723 724 731 public Vector getRelatedMessages(MMObjectNode node, Comparator ci) { 732 Vector result = new Vector(); 734 Enumeration relatedMessages; 735 736 MMObjectNode channel = isPostedInChannel(node); 737 MMObjectNode community = channelBuilder.communityParent(channel); 738 String kind; 739 if (community != null) { 740 kind = (String ) community.getValue("kind"); 741 } else { 742 kind = "forum"; 743 } 744 745 if (kind.equalsIgnoreCase("chatbox")) { 746 relatedMessages = getTemporaryRelated(node, "message").elements(); 747 } else { 748 relatedMessages = getReplies(node); 749 } 750 751 if (relatedMessages == null) return result; 752 753 MMObjectNode relmsg = null; 754 int parent = node.getNumber(); 755 while (relatedMessages.hasMoreElements()) { 756 relmsg = (MMObjectNode) relatedMessages.nextElement(); 759 if (relmsg.getIntValue(F_THREAD) == parent) 760 result.add(relmsg); 761 } 762 Collections.sort(result, ci); 763 return result; 764 } 765 766 770 private int addRelatedNode(MMObjectNode node, int otypeWanted, int count, int offset, Vector result) { 771 if ((node != null) && 772 (node.getIntValue("otype") == otypeWanted)) { 773 count += 1; 774 if (count > offset) { 775 result.add(node); 776 } 777 } 778 return count; 779 } 780 781 786 private int addRelated(int number, int otypeWanted, int count, int offset, Vector result) { 787 MMObjectNode node = getNode(number); 788 return addRelatedNode(node, otypeWanted, count, offset, result); 789 } 790 791 796 private int addRelated(Object key, int otypeWanted, int count, int offset, Vector result) { 797 if (key != null) { 798 MMObjectNode node = (MMObjectNode) temporaryNodes.get("" + key); 799 count = addRelatedNode(node, otypeWanted, count, offset, result); 800 } 801 return count; 802 } 803 804 809 public Vector getTemporaryRelated(MMObjectNode node, String wtype) { 810 return getTemporaryRelated(node, wtype, 0, Integer.MAX_VALUE); 811 } 812 813 818 public Vector getTemporaryRelated(MMObjectNode node, String wtype, 819 int offset, int max) { 820 Vector result = new Vector(); 821 if (max <= 0) return result; 822 MMObjectNode tmpInsRel; 823 boolean found; 824 int otypewanted = mmb.getTypeDef().getIntValue(wtype); 825 int count = 0; 826 827 int number = -1; 829 String _number = (String ) node.getValue("_number"); 830 if (_number == null) number = node.getNumber(); 831 832 Iterator tmpInsRels = temporaryNodes.keySet().iterator(); 834 while ((count < (offset + max)) && tmpInsRels.hasNext()) { 835 tmpInsRel = (MMObjectNode) temporaryNodes.get(tmpInsRels.next()); 836 if (tmpInsRel != null) { 837 if (tmpInsRel.getBuilder() instanceof InsRel) { 838 found = false; 839 if (_number != null) { 841 found = _number.equals(tmpInsRel.getStringValue("_snumber")); 842 } else { 843 found = (number == tmpInsRel.getIntValue("snumber")); 844 } 845 if (found) { int dnumber = tmpInsRel.getIntValue("dnumber"); 847 if (dnumber > -1) { 848 count = addRelated(dnumber, otypewanted, count, offset, result); 849 } else { 850 count = addRelated(tmpInsRel.getValue("_dnumber"), 851 otypewanted, count, offset, result); 852 } 853 } else { 854 if (_number != null) { 855 found = _number.equals(tmpInsRel.getStringValue("_dnumber")); 856 } else { 857 found = (number == tmpInsRel.getIntValue("dnumber")); 858 } 859 if (found) { int snumber = tmpInsRel.getIntValue("snumber"); 861 if (snumber > -1) { 862 count = addRelated(snumber, otypewanted, count, offset, result); 863 } else { 864 count = addRelated(tmpInsRel.getValue("_snumber"), 865 otypewanted, count, offset, result); 866 } 867 } 868 } 869 } 870 } 871 } 872 return result; 873 } 874 875 892 private void addListTags(Vector items, int listheadItemNr, int listtailItemNr, 893 int depthItemNr, int fieldsCount, String openTag, String closeTag) { 894 int depth; 895 int previousDepth = 0; 896 int itemNr = 0; 897 int itemsCount = items.size(); 898 String prefix, postfix; 899 while (itemNr < itemsCount) { 900 depth = (Integer.decode((String ) items.elementAt(itemNr + depthItemNr))).intValue(); 901 if (itemNr == 0) { 902 prefix = openTag; while (previousDepth < depth) { 904 prefix += openTag; previousDepth++; 906 } 907 } else if (depth > previousDepth) { 908 prefix = openTag; } else { 910 prefix = ""; 911 } 912 postfix = ""; 913 if (depth < previousDepth) { 914 while (previousDepth > depth) { 915 prefix += closeTag; previousDepth--; 917 } 918 } 919 if (itemNr == itemsCount - fieldsCount) { 920 while (depth > 0) { 921 postfix += closeTag; depth--; 923 } 924 postfix += closeTag; 925 } 926 items.set(itemNr + listheadItemNr, prefix); 927 items.set(itemNr + listtailItemNr, postfix); 928 itemNr += fieldsCount; 929 previousDepth = depth; 930 } 931 } 932 933 938 public void removeNode(MMObjectNode node) { 939 removeNode(node, false); 940 } 941 942 950 public void removeNode(MMObjectNode node, boolean recursive) { 951 log.service("removeNode(): node=" + node.getNumber()); 952 953 if (!(node.getBuilder() instanceof Message)) { 955 log.error(node.getNumber() + " is of type " + node.getName() + " instead of Message"); 956 return; 957 } 958 959 MMObjectNode relmsg; 962 for (Enumeration messages = getReplies(node); messages.hasMoreElements();) { 963 relmsg = (MMObjectNode) messages.nextElement(); 964 if (relmsg.getIntValue(F_THREAD) == node.getNumber()) { 968 if (recursive) { 970 removeNode(relmsg, true); 971 } else { 972 log.error("Can't delete Message " + node.getNumber() + " because it has child Messages."); 973 return; 974 } 975 } 976 } 977 InsRel insrel = mmb.getInsRel(); 979 insrel.removeRelations(node); 980 if (node.hasRelations()) { 981 log.error("Failed to remove node relations"); 982 } 983 super.removeNode(node); 985 } 986 987 public ThreadStats getNrMsgAndHighSeq(MMObjectNode node) { 988 992 int sequence = -1; 993 int highestSequence = -1; 994 int messageCount = 0; 995 MMObjectNode msg; 996 for (Enumeration messages = getReplies(node); messages.hasMoreElements();) { 997 msg = (MMObjectNode) messages.nextElement(); 998 if (msg.getIntValue(F_THREAD) == node.getNumber()) { 999 sequence = msg.getIntValue(F_SEQUENCE); 1000 if (sequence > highestSequence) highestSequence = sequence; 1001 1003 ThreadStats cs = getNrMsgAndHighSeq(msg); 1004 messageCount += cs.messageCount + 1; 1005 if (cs.highestSequence > highestSequence) highestSequence = cs.highestSequence; 1006 } 1007 } 1008 return new ThreadStats(node.getNumber(), messageCount, highestSequence); 1009 } 1010 1011 1016 public boolean hasReplies(MMObjectNode node) { 1017 return getNrMsgAndHighSeq(node).messageCount > 0; 1018 } 1019 1020 1029 public Enumeration getReplies(MMObjectNode node) { 1030 return node.getRelatedNodes("message").elements(); 1031 } 1032 1033 1055 public Object getValue(MMObjectNode node, String field) { 1056 if (field.equals(F_TIMESTAMP)) { 1059 TimeStamp ts = new TimeStamp(); if (super.getValue(node, F_TIMESTAMP) == null) { if (getField(F_TIMESTAMP) == null) { ts = getTimeStamp(node); 1063 } 1064 } 1065 return "" + ts.getTime(); 1066 } 1067 if (field.equals(F_TIMESTAMPSEC)) { 1068 long ts = node.getLongValue(F_TIMESTAMP) / 1000; 1069 return new Long (ts); 1070 } 1071 if (field.equals(F_RE_SUBJECT)) { 1072 String subject = node.getStringValue(F_SUBJECT); 1073 if (subject.startsWith("RE: ")) return subject; else return ("RE: " + subject); 1074 } 1075 if (field.equals(F_REPLY_COUNT)) { 1076 return new Integer (getNrMsgAndHighSeq(node).messageCount); 1077 } 1078 if (field.equals(F_HAS_REPLIES)) { 1079 return Boolean.valueOf(hasReplies(node)); 1080 } 1081 if (field.equals(F_PARENT)) { 1082 return node.getValue(F_THREAD); 1083 } 1084 if (field.startsWith("substring")) { 1089 1092 int commaPos = field.lastIndexOf('x'); 1093 String realField = field.substring(10, commaPos); String value = (String ) node.getValue(realField); 1095 int size = Integer.decode(field.substring(commaPos + 1, field.length() - 1)).intValue(); 1096 if (size < value.length()) 1097 return value.substring(0, size); 1098 else 1099 return value; 1100 } 1102 Object o = super.getValue(node, field); 1103 if (o instanceof String ) { 1104 if ((field.indexOf("html(") < 0) && (field.indexOf("html_") < 0)) 1105 o = getHTML((String ) o); 1106 } 1107 return o; 1108 } 1109 1110 1118 protected Object executeFunction(MMObjectNode node, String function, String field) { 1119 if (function.equals(F_GET_INFO_VALUE)) { 1120 return getInfoField(node, field); 1121 } else { 1122 return super.executeFunction(node, function, field); 1123 } 1124 } 1125 1126 1129 public String replace(PageInfo sp, StringTokenizer tok) { 1130 1132 if (!tok.hasMoreElements()) { 1133 log.error("replace(): message number expected after $MOD-BUILDER-message-."); 1134 return ""; 1135 } 1136 String tmp = tok.nextToken(); 1137 MMObjectNode message = getNode(tmp); 1138 if (message == null) message = (MMObjectNode) temporaryNodes.get(tmp.trim()); 1140 if (message == null) { 1141 log.error("Message with id '" + tmp + "' cannot be found."); 1142 return ""; 1143 } 1144 1145 if (tok.hasMoreElements()) { 1146 String cmd = tok.nextToken(); 1147 if (cmd.equals("DEL")) removeNode(message, true); 1148 if (cmd.equals("GETINFOFIELD")) return getInfoField(message, tok.nextToken()); 1149 if (cmd.equals("SETINFOFIELD")) { 1150 setInfoField(message, tok.nextToken(), tok.nextToken()); 1151 message.commit(); 1152 } 1153 } 1154 return ""; 1155 } 1156 1157 1165 private void setInfoField(MMObjectNode message, String field, String value) { 1166 value = remove(value, "\n=,\""); 1167 String info = message.getStringValue(F_INFO); 1168 StringTagger tagger = new StringTagger(info, '\n', '=', ',', '\"'); 1169 tagger.setValue(field, value); 1170 String key = ""; 1171 String content = ""; 1172 for (Iterator i = tagger.keySet().iterator(); i.hasNext();) { 1173 key = (String ) i.next(); 1174 content += key + "=" + tagger.Value(key) + "\n"; 1175 } 1176 message.setValue(F_INFO, content); 1177 } 1178 1179 private String remove(String s, String r) { 1180 if (s == null) return null; 1181 String result = ""; 1182 for (int i = 0; i < s.length(); i++) { 1183 char c = s.charAt(i); 1184 if (r.indexOf(c) < 0) 1185 result = result + c; 1186 } 1187 return result; 1188 } 1189 1190 1198 private String getInfoField(MMObjectNode message, String field) { 1199 String info = message.getStringValue(F_INFO); 1200 StringTagger tagger = new StringTagger(info, '\n', '=', ',', '\"'); 1201 return getHTML(tagger.Value(field)); 1202 } 1203 1204 1207 public TimeStamp getTimeStamp(MMObjectNode node) { 1208 return new TimeStamp((Integer ) node.getValue("timestampl"), (Integer ) node.getValue("timestamph")); 1209 } 1210 1211 1216 public MMObjectNode isPostedInChannel(MMObjectNode node) { 1217 while (node.getBuilder() instanceof Message) { 1218 node = getNode(node.getIntValue(F_THREAD)); 1219 } 1220 return node; 1221 } 1222 1223 1226 synchronized public String getNewTemporaryKey() { 1227 return (tmpNumberPrefix + tmpNumbers++); 1228 } 1229} 1230 1231 1234class ThreadStats { 1235 1236 public int thread = -1; 1237 1238 public int messageCount = 0; 1239 1240 public int highestSequence = 0; 1241 1242 1248 public ThreadStats(int thread, int messageCount, int highestSequence) { 1249 this.thread = thread; 1250 this.messageCount = messageCount; 1251 this.highestSequence = highestSequence; 1252 } 1253} 1254 | Popular Tags |