aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Ivov <emcho@jitsi.org>2005-11-02 14:08:43 +0000
committerEmil Ivov <emcho@jitsi.org>2005-11-02 14:08:43 +0000
commitc82e7e1327fd89ec30929a7d4e529039b751bf41 (patch)
treeb2694122644e90a21bd0348f81a53a45841a37dd
parent462770b17bdbdffcf61b8862635738e46d58e505 (diff)
downloadjitsi-c82e7e1327fd89ec30929a7d4e529039b751bf41.zip
jitsi-c82e7e1327fd89ec30929a7d4e529039b751bf41.tar.gz
jitsi-c82e7e1327fd89ec30929a7d4e529039b751bf41.tar.bz2
Initial sip-communicator-1.0 commit
-rw-r--r--doc/.cvsignore1
-rw-r--r--doc/AssigningAddressPreferences.sxibin0 -> 13734 bytes
-rw-r--r--lib/.project11
-rw-r--r--lib/JainSipApi1.1.jarbin0 -> 49408 bytes
-rw-r--r--lib/Stun4J.jarbin0 -> 113987 bytes
-rw-r--r--lib/architectureviewer1.1.jarbin0 -> 218708 bytes
-rw-r--r--lib/bundle/.#junit.jar.1.8bin0 -> 119518 bytes
-rw-r--r--lib/bundle/architectureviewer1.1.jarbin0 -> 217716 bytes
-rw-r--r--lib/bundle/bundlerepository.jarbin0 -> 113208 bytes
-rw-r--r--lib/bundle/exportfilter.jarbin0 -> 2796 bytes
-rw-r--r--lib/bundle/importfilter.jarbin0 -> 1722 bytes
-rw-r--r--lib/bundle/importrange.jarbin0 -> 397 bytes
-rw-r--r--lib/bundle/junit.jarbin0 -> 119527 bytes
-rw-r--r--lib/bundle/listener.jarbin0 -> 2533 bytes
-rw-r--r--lib/bundle/servicebinder.jarbin0 -> 70242 bytes
-rw-r--r--lib/bundle/shell.jarbin0 -> 39691 bytes
-rw-r--r--lib/bundle/shellgui.jarbin0 -> 11730 bytes
-rw-r--r--lib/bundle/shellplugin.jarbin0 -> 29764 bytes
-rw-r--r--lib/bundle/shelltui.jarbin0 -> 5417 bytes
-rw-r--r--lib/bundle/simple.jarbin0 -> 4775 bytes
-rw-r--r--lib/bundle/tablelayout.jarbin0 -> 14489 bytes
-rw-r--r--lib/jaxen-1.1-beta-8.jarbin0 -> 231706 bytes
-rw-r--r--lib/jmf-all/jmf.jarbin0 -> 1914158 bytes
-rw-r--r--lib/jmf-lin/jmf-native.jarbin0 -> 589695 bytes
-rw-r--r--lib/jmf-lin/jmf.jarbin0 -> 1832080 bytes
-rw-r--r--lib/jmf-lin/libjmutil.so.jarbin0 -> 15281 bytes
-rw-r--r--lib/jmf-sol/jmf-native.jarbin0 -> 2214839 bytes
-rw-r--r--lib/jmf-sol/jmf.jarbin0 -> 2199950 bytes
-rw-r--r--lib/jmf-sol/libjmutil.so.jarbin0 -> 21507 bytes
-rw-r--r--lib/jmf-win/jmf-native.jarbin0 -> 2064348 bytes
-rw-r--r--lib/jmf-win/jmf.jarbin0 -> 2084994 bytes
-rw-r--r--lib/jmf-win/sound.jarbin0 -> 294070 bytes
-rw-r--r--lib/junit.jarbin0 -> 121070 bytes
-rw-r--r--lib/logging.properties54
-rw-r--r--lib/moduleloader.jarbin0 -> 35422 bytes
-rw-r--r--lib/nist-sdp-1.0.jarbin0 -> 127470 bytes
-rw-r--r--lib/nist-sip-1.2.jarbin0 -> 439869 bytes
-rw-r--r--lib/oscar.client.run.properties67
-rw-r--r--lib/oscar.jarbin0 -> 167414 bytes
-rw-r--r--lib/oscar.unit.test.properties79
-rw-r--r--lib/osgi.jarbin0 -> 22575 bytes
-rw-r--r--lib/servicebinder.jarbin0 -> 70213 bytes
-rw-r--r--lib/skinlf.jarbin0 -> 332417 bytes
-rw-r--r--src/net/java/sip/communicator/.cvsignore1
-rw-r--r--src/net/java/sip/communicator/impl/configuration/.cvsignore0
-rw-r--r--src/net/java/sip/communicator/impl/configuration/Activator.java74
-rw-r--r--src/net/java/sip/communicator/impl/configuration/ChangeEventDispatcher.java433
-rw-r--r--src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java846
-rw-r--r--src/net/java/sip/communicator/impl/configuration/configuration.manifest.mf18
-rw-r--r--src/net/java/sip/communicator/impl/configuration/res/configuration.manifest.mf7
-rw-r--r--src/net/java/sip/communicator/impl/configuration/xml/XMLConfUtils.java83
-rw-r--r--src/net/java/sip/communicator/impl/gui/Activator.java45
-rw-r--r--src/net/java/sip/communicator/impl/gui/UIServiceImpl.java63
-rw-r--r--src/net/java/sip/communicator/impl/gui/gui.manifest.mf6
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/CallList.java19
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/CallPanel.java54
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/CommunicatorMain.java96
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/ContactItem.java54
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/ContactList.java23
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/ContactListPanel.java81
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/ContactListTree.java7
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/ContactPanel.java138
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/DialPanel.java71
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/LookAndFeelConstants.java284
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/MainFrame.java58
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/MainTabbedPane.java30
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/Menu.java44
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/QuickMenu.java69
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/Status.java29
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/StatusPanel.java40
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/User.java13
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/customcontrols/SIPCommButton.java125
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusIcon.java40
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusSelectorBox.java117
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/addContactIcon.pngbin0 -> 630 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/call.gifbin0 -> 1247 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/callIcon.pngbin0 -> 1229 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/callRollover.gifbin0 -> 1626 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/combobox.pngbin0 -> 840 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/configureIcon.pngbin0 -> 892 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/hangUp.gifbin0 -> 1663 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/hangUpRollover.gifbin0 -> 1626 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/hangupIcon.pngbin0 -> 624 bytes
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonBg.gifbin0 -> 1247 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonRolloverBg.gifbin0 -> 1626 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim.pngbin0 -> 4876 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim16.pngbin0 -> 737 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq.pngbin0 -> 6386 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq16.pngbin0 -> 817 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_away.pngbin0 -> 360 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_dnd.pngbin0 -> 666 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_ffc.pngbin0 -> 884 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_invisible.pngbin0 -> 1009 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_na.pngbin0 -> 387 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_occupied.pngbin0 -> 761 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_offline.pngbin0 -> 643 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber16.pngbin0 -> 807 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber2.pngbin0 -> 5847 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn.pngbin0 -> 7091 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn16.pngbin0 -> 920 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn2-16.pngbin0 -> 917 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype.pngbin0 -> 6653 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype16.pngbin0 -> 945 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo.pngbin0 -> 6313 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo16.pngbin0 -> 884 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down1.pngbin0 -> 343 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down2.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down3.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left1.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left2.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left3.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right1.pngbin0 -> 347 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right2.pngbin0 -> 347 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right3.pngbin0 -> 347 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up1.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up2.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up3.pngbin0 -> 341 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/background.pngbin0 -> 177 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button0.pngbin0 -> 1195 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button1.pngbin0 -> 822 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button2.pngbin0 -> 1692 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button3.pngbin0 -> 803 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button4.pngbin0 -> 822 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button5.pngbin0 -> 795 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button6.pngbin0 -> 605 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button7.pngbin0 -> 822 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button8.pngbin0 -> 822 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button9.pngbin0 -> 1158 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check1.pngbin0 -> 1403 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check2.pngbin0 -> 1525 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/empty.pngbin0 -> 183 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry1.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry2.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_bottom1.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_left1.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_right1.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_top1.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_end.pngbin0 -> 133 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_start.pngbin0 -> 125 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_end.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_start.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left.pngbin0 -> 280 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_end.pngbin0 -> 334 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_start.pngbin0 -> 326 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right.pngbin0 -> 322 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_end.pngbin0 -> 395 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_start.pngbin0 -> 398 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_end.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_start.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gtkrc1224
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_horiz_thumb.pngbin0 -> 281 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_vert_thumb.pngbin0 -> 254 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/hline.pngbin0 -> 117 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/htrough.pngbin0 -> 946 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/mainbackground.pngbin0 -> 3300 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_selected.pngbin0 -> 224 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_shadow.pngbin0 -> 209 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menubar.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook1.pngbin0 -> 144 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook2.pngbin0 -> 1131 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook3.pngbin0 -> 1864 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook4.pngbin0 -> 1085 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook5.pngbin0 -> 1728 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook6.pngbin0 -> 943 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook7.pngbin0 -> 605 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option1.pngbin0 -> 706 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option2.pngbin0 -> 758 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu.pngbin0 -> 3536 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu_disabled.pngbin0 -> 1836 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz1.pngbin0 -> 1803 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz2.pngbin0 -> 2487 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_vert1.pngbin0 -> 1796 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow1.pngbin0 -> 288 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow2.pngbin0 -> 288 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_horiz1.pngbin0 -> 1085 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth1.pngbin0 -> 295 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth2.pngbin0 -> 282 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vert1.pngbin0 -> 1087 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth1.pngbin0 -> 399 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth2.pngbin0 -> 289 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_downarrow.pngbin0 -> 218 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_hhandle.pngbin0 -> 228 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_leftarrow.pngbin0 -> 222 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_rightarrow.pngbin0 -> 226 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_uparrow.pngbin0 -> 213 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_vhandle.pngbin0 -> 230 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/textborder.pngbin0 -> 419 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vline.pngbin0 -> 412 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vtrough.pngbin0 -> 886 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Computer16.gifbin0 -> 1006 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Default.gifbin0 -> 905 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Error.gifbin0 -> 1556 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewDetails18.gifbin0 -> 151 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewList18.gifbin0 -> 172 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Floppy16.gifbin0 -> 1011 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Folder16.gifbin0 -> 960 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderNew18.gifbin0 -> 1040 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderUp18.gifbin0 -> 1020 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FrameDefault.gifbin0 -> 932 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Harddisk16.gifbin0 -> 939 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Home18.gifbin0 -> 1030 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Inform.gifbin0 -> 1627 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Information.gifbin0 -> 1570 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Page16.gifbin0 -> 149 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Question.gifbin0 -> 1535 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/TreeClosed.gifbin0 -> 965 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Warn.gifbin0 -> 1473 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/CosmicGelDj4.gifbin0 -> 617 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/activetitle.PNGbin0 -> 215 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/aquabackground.PNGbin0 -> 614 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/bondiblue.PNGbin0 -> 194 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close.PNGbin0 -> 801 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_disabled.PNGbin0 -> 1018 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_down.PNGbin0 -> 1155 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify.PNGbin0 -> 757 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_disabled.PNGbin0 -> 1050 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_down.PNGbin0 -> 1139 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/inactivetitle.PNGbin0 -> 188 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kde.themerc132
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kfmbackground.PNGbin0 -> 194 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize.PNGbin0 -> 971 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize_disabled.PNGbin0 -> 1053 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximizedown.PNGbin0 -> 984 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/menu.PNGbin0 -> 919 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/panelx.PNGbin0 -> 159 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_selected.pngbin0 -> 2100 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_unselected.pngbin0 -> 2000 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottom.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomleft.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomright.pngbin0 -> 80 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_left.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_right.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topleft.pngbin0 -> 296 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topright.pngbin0 -> 294 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/skinlf-themepack.xml18
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_down.pngbin0 -> 433 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_down.pngbin0 -> 531 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_left.pngbin0 -> 523 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_right.pngbin0 -> 515 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_up.pngbin0 -> 512 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_left.pngbin0 -> 446 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_right.pngbin0 -> 441 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_down.pngbin0 -> 433 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_left.pngbin0 -> 446 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_right.pngbin0 -> 441 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_up.pngbin0 -> 427 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_up.pngbin0 -> 427 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_active.pngbin0 -> 720 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_in.pngbin0 -> 543 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_out.pngbin0 -> 543 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_in.pngbin0 -> 576 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_normal_in.pngbin0 -> 720 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_out.pngbin0 -> 576 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_rollover_out.pngbin0 -> 579 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_selected.pngbin0 -> 579 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_in.pngbin0 -> 567 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_out.pngbin0 -> 436 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/empty.pngbin0 -> 183 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/gtkrc1079
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_horizontal.pngbin0 -> 155 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_vertical.pngbin0 -> 155 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menu_border.pngbin0 -> 171 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menuitem.pngbin0 -> 682 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu.pngbin0 -> 758 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_disabled.pngbin0 -> 521 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_rollover.pngbin0 -> 758 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress.pngbin0 -> 314 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress_track.pngbin0 -> 175 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_in.pngbin0 -> 531 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_out.pngbin0 -> 468 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_htrough.pngbin0 -> 400 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_vtrough.pngbin0 -> 380 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider.pngbin0 -> 166 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_disabled.pngbin0 -> 166 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_horizontal.pngbin0 -> 623 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_vertical.pngbin0 -> 611 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_horizontal.pngbin0 -> 890 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_horizontal.pngbin0 -> 898 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_vertical.pngbin0 -> 734 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_vertical.pngbin0 -> 734 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_downarrow.pngbin0 -> 217 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_hhandle.pngbin0 -> 169 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_leftarrow.pngbin0 -> 222 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_rightarrow.pngbin0 -> 226 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_uparrow.pngbin0 -> 213 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_vhandle.pngbin0 -> 159 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active.pngbin0 -> 427 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active_bottom.pngbin0 -> 573 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_border.pngbin0 -> 382 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_in.pngbin0 -> 543 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_out.pngbin0 -> 543 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_in.pngbin0 -> 720 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_out.pngbin0 -> 576 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_rollover_out.pngbin0 -> 579 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/trough.pngbin0 -> 166 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Computer.gifbin0 -> 938 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Default.gifbin0 -> 992 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/DetailsView.gifbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Error.gifbin0 -> 1661 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/File.gifbin0 -> 891 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/FloppyDrive.gifbin0 -> 914 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HardDrive.gifbin0 -> 886 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HomeFolder.gifbin0 -> 897 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Inform.gifbin0 -> 1631 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/ListView.gifbin0 -> 96 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/NewFolder.gifbin0 -> 887 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Question.gifbin0 -> 1445 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeClosed.gifbin0 -> 902 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeOpen.gifbin0 -> 906 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/UpFolder.gifbin0 -> 888 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Warn.gifbin0 -> 1493 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Window.gifbin0 -> 898 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close.pngbin0 -> 819 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_disabled.pngbin0 -> 688 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_down.pngbin0 -> 817 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_rollover.pngbin0 -> 811 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/kde.themerc90
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize.pngbin0 -> 819 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_disabled.pngbin0 -> 688 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_down.pngbin0 -> 831 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_rollover.pngbin0 -> 822 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize.pngbin0 -> 819 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_disabled.pngbin0 -> 688 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_down.pngbin0 -> 841 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_rollover.pngbin0 -> 831 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_selected.pngbin0 -> 2100 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_unselected.pngbin0 -> 2000 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottom.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomleft.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomright.pngbin0 -> 80 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_left.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_right.pngbin0 -> 79 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topleft.pngbin0 -> 296 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topright.pngbin0 -> 294 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/skinlf-themepack.xml57
-rw-r--r--src/net/java/sip/communicator/impl/history/Activator.java13
-rw-r--r--src/net/java/sip/communicator/impl/history/DBStructSerializer.java237
-rw-r--r--src/net/java/sip/communicator/impl/history/HistoryImpl.java197
-rw-r--r--src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java163
-rw-r--r--src/net/java/sip/communicator/impl/history/HistoryServiceImpl.java255
-rw-r--r--src/net/java/sip/communicator/impl/history/HistoryWriterImpl.java134
-rw-r--r--src/net/java/sip/communicator/impl/history/history.manifest.mf33
-rw-r--r--src/net/java/sip/communicator/impl/history/history.metadata.xml22
-rw-r--r--src/net/java/sip/communicator/impl/media/Activator.java19
-rw-r--r--src/net/java/sip/communicator/impl/media/MediaControl.java144
-rw-r--r--src/net/java/sip/communicator/impl/media/MediaDispatcher.java119
-rw-r--r--src/net/java/sip/communicator/impl/media/MediaServiceImpl.java200
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/ConfigurationListener.java28
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/DirectSoundAuto.java112
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/JMFInit.java395
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/JavaSoundAuto.java78
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/JavaSoundDetector.java37
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/MediaConfiguration.java189
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/SunVideoAuto.java183
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/SunVideoPlusAuto.java393
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/V4LAuto.java70
-rw-r--r--src/net/java/sip/communicator/impl/media/configuration/VFWAuto.java52
-rw-r--r--src/net/java/sip/communicator/impl/media/media.manifest.mf23
-rw-r--r--src/net/java/sip/communicator/impl/media/media.metadata.xml17
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/.#NetworkAddressManagerServiceImpl.java.1.6562
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/.cvsignore0
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/Activator.java80
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/AddressDiagnosticsKit.java384
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/AddressPool.java80
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/AddressPoolEntry.java275
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/AddressPreference.java109
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/BlockingRequestSender.java96
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/FirewallDescriptor.java204
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java634
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/StunClient.java291
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/StunDiscoveryReport.java143
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf14
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/res/netaddr.manifest.mf7
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/Activator.java44
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipProtocolProviderServiceImpl.java230
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf7
-rw-r--r--src/net/java/sip/communicator/impl/resources/Activator.java14
-rw-r--r--src/net/java/sip/communicator/impl/resources/FileAccessServiceImpl.java267
-rw-r--r--src/net/java/sip/communicator/impl/resources/TempFileManager.java212
-rw-r--r--src/net/java/sip/communicator/impl/resources/resources.manifest.mf22
-rw-r--r--src/net/java/sip/communicator/impl/resources/resources.metadata.xml18
-rw-r--r--src/net/java/sip/communicator/launcher/Main.java131
-rw-r--r--src/net/java/sip/communicator/service/callhistory/CallHistoryService.java15
-rw-r--r--src/net/java/sip/communicator/service/configuration/ConfigurationService.java201
-rw-r--r--src/net/java/sip/communicator/service/configuration/PropertyVetoException.java50
-rw-r--r--src/net/java/sip/communicator/service/configuration/event/PropertyChangeEvent.java109
-rw-r--r--src/net/java/sip/communicator/service/configuration/event/PropertyChangeListener.java29
-rw-r--r--src/net/java/sip/communicator/service/configuration/event/VetoableChangeListener.java46
-rw-r--r--src/net/java/sip/communicator/service/configuration/gravity-metadata.xml29
-rw-r--r--src/net/java/sip/communicator/service/gui/UIService.java155
-rw-r--r--src/net/java/sip/communicator/service/gui/event/UserActionListener.java44
-rw-r--r--src/net/java/sip/communicator/service/history/DefaultQueryResultSet.java65
-rw-r--r--src/net/java/sip/communicator/service/history/History.java38
-rw-r--r--src/net/java/sip/communicator/service/history/HistoryID.java216
-rw-r--r--src/net/java/sip/communicator/service/history/HistoryReader.java74
-rw-r--r--src/net/java/sip/communicator/service/history/HistoryService.java62
-rw-r--r--src/net/java/sip/communicator/service/history/HistoryWriter.java36
-rw-r--r--src/net/java/sip/communicator/service/history/QueryResultSet.java39
-rw-r--r--src/net/java/sip/communicator/service/history/records/HistoryRecord.java90
-rw-r--r--src/net/java/sip/communicator/service/history/records/HistoryRecordStructure.java76
-rw-r--r--src/net/java/sip/communicator/service/history/records/TextType.java23
-rw-r--r--src/net/java/sip/communicator/service/media/MediaService.java86
-rw-r--r--src/net/java/sip/communicator/service/media/event/MediaEvent.java24
-rw-r--r--src/net/java/sip/communicator/service/media/event/MediaListener.java19
-rw-r--r--src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java19
-rw-r--r--src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java75
-rw-r--r--src/net/java/sip/communicator/service/protocol/AuthorizationHandler.java18
-rw-r--r--src/net/java/sip/communicator/service/protocol/Call.java96
-rw-r--r--src/net/java/sip/communicator/service/protocol/CallParticipant.java118
-rw-r--r--src/net/java/sip/communicator/service/protocol/CallParticipantState.java234
-rw-r--r--src/net/java/sip/communicator/service/protocol/Contact.java72
-rw-r--r--src/net/java/sip/communicator/service/protocol/ContactList.java22
-rw-r--r--src/net/java/sip/communicator/service/protocol/DefaultCallParticipant.java342
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationNotSupportedException.java30
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSet.java15
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetBasicInstantMessaging.java22
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java87
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetCallTransfer.java27
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java25
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetPresence.java37
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetTelephonyConferencing.java47
-rw-r--r--src/net/java/sip/communicator/service/protocol/PresenceStatus.java135
-rw-r--r--src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java178
-rw-r--r--src/net/java/sip/communicator/service/protocol/SecurityAuthority.java17
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/CallChangeListener.java19
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/CallListener.java29
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/CallParticipantChangeEvent.java84
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/CallParticipantControlEvent.java62
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/CallParticipantListener.java19
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/CallReceivedEvent.java37
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileListener.java20
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/PresenceStatusListener.java20
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/ProviderChangeListener.java25
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/ProviderStatusChangeEvent.java67
-rw-r--r--src/net/java/sip/communicator/service/resources/FileAccessService.java124
-rw-r--r--src/net/java/sip/communicator/sick/netaddr/.cvsignore0
-rw-r--r--src/net/java/sip/communicator/slick/.cvsignore0
-rw-r--r--src/net/java/sip/communicator/slick/netaddr/.cvsignore0
-rw-r--r--src/net/java/sip/communicator/slick/netaddr/TestAddressPool.java21
-rw-r--r--src/net/java/sip/communicator/util/Activator.java35
-rw-r--r--src/net/java/sip/communicator/util/Assert.java80
-rw-r--r--src/net/java/sip/communicator/util/BidirectionalIterator.java38
-rw-r--r--src/net/java/sip/communicator/util/EnumerationBase.java124
-rw-r--r--src/net/java/sip/communicator/util/Logger.java353
-rw-r--r--src/net/java/sip/communicator/util/QuoteTokenizer.java288
-rw-r--r--src/net/java/sip/communicator/util/ScLogFormatter.java116
-rw-r--r--src/net/java/sip/communicator/util/util.manifest.mf17
-rw-r--r--src/net/java/sip/communicator/util/xml/XMLException.java45
-rw-r--r--src/net/java/sip/communicator/util/xml/XMLUtils.java403
451 files changed, 17885 insertions, 0 deletions
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644
index 0000000..9e5bfb4
--- /dev/null
+++ b/doc/.cvsignore
@@ -0,0 +1 @@
+api \ No newline at end of file
diff --git a/doc/AssigningAddressPreferences.sxi b/doc/AssigningAddressPreferences.sxi
new file mode 100644
index 0000000..c8ac0aa
--- /dev/null
+++ b/doc/AssigningAddressPreferences.sxi
Binary files differ
diff --git a/lib/.project b/lib/.project
new file mode 100644
index 0000000..14aa1aa
--- /dev/null
+++ b/lib/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>lib</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/lib/JainSipApi1.1.jar b/lib/JainSipApi1.1.jar
new file mode 100644
index 0000000..fede379
--- /dev/null
+++ b/lib/JainSipApi1.1.jar
Binary files differ
diff --git a/lib/Stun4J.jar b/lib/Stun4J.jar
new file mode 100644
index 0000000..7e17300
--- /dev/null
+++ b/lib/Stun4J.jar
Binary files differ
diff --git a/lib/architectureviewer1.1.jar b/lib/architectureviewer1.1.jar
new file mode 100644
index 0000000..eacf55d
--- /dev/null
+++ b/lib/architectureviewer1.1.jar
Binary files differ
diff --git a/lib/bundle/.#junit.jar.1.8 b/lib/bundle/.#junit.jar.1.8
new file mode 100644
index 0000000..b3a1723
--- /dev/null
+++ b/lib/bundle/.#junit.jar.1.8
Binary files differ
diff --git a/lib/bundle/architectureviewer1.1.jar b/lib/bundle/architectureviewer1.1.jar
new file mode 100644
index 0000000..6e63fc3
--- /dev/null
+++ b/lib/bundle/architectureviewer1.1.jar
Binary files differ
diff --git a/lib/bundle/bundlerepository.jar b/lib/bundle/bundlerepository.jar
new file mode 100644
index 0000000..9591907
--- /dev/null
+++ b/lib/bundle/bundlerepository.jar
Binary files differ
diff --git a/lib/bundle/exportfilter.jar b/lib/bundle/exportfilter.jar
new file mode 100644
index 0000000..2e02485
--- /dev/null
+++ b/lib/bundle/exportfilter.jar
Binary files differ
diff --git a/lib/bundle/importfilter.jar b/lib/bundle/importfilter.jar
new file mode 100644
index 0000000..5b4960f
--- /dev/null
+++ b/lib/bundle/importfilter.jar
Binary files differ
diff --git a/lib/bundle/importrange.jar b/lib/bundle/importrange.jar
new file mode 100644
index 0000000..af1eaff
--- /dev/null
+++ b/lib/bundle/importrange.jar
Binary files differ
diff --git a/lib/bundle/junit.jar b/lib/bundle/junit.jar
new file mode 100644
index 0000000..f2f60c8
--- /dev/null
+++ b/lib/bundle/junit.jar
Binary files differ
diff --git a/lib/bundle/listener.jar b/lib/bundle/listener.jar
new file mode 100644
index 0000000..f127e34
--- /dev/null
+++ b/lib/bundle/listener.jar
Binary files differ
diff --git a/lib/bundle/servicebinder.jar b/lib/bundle/servicebinder.jar
new file mode 100644
index 0000000..59d1ba3
--- /dev/null
+++ b/lib/bundle/servicebinder.jar
Binary files differ
diff --git a/lib/bundle/shell.jar b/lib/bundle/shell.jar
new file mode 100644
index 0000000..322c264
--- /dev/null
+++ b/lib/bundle/shell.jar
Binary files differ
diff --git a/lib/bundle/shellgui.jar b/lib/bundle/shellgui.jar
new file mode 100644
index 0000000..0376454
--- /dev/null
+++ b/lib/bundle/shellgui.jar
Binary files differ
diff --git a/lib/bundle/shellplugin.jar b/lib/bundle/shellplugin.jar
new file mode 100644
index 0000000..005b051
--- /dev/null
+++ b/lib/bundle/shellplugin.jar
Binary files differ
diff --git a/lib/bundle/shelltui.jar b/lib/bundle/shelltui.jar
new file mode 100644
index 0000000..8942385
--- /dev/null
+++ b/lib/bundle/shelltui.jar
Binary files differ
diff --git a/lib/bundle/simple.jar b/lib/bundle/simple.jar
new file mode 100644
index 0000000..8a4743f
--- /dev/null
+++ b/lib/bundle/simple.jar
Binary files differ
diff --git a/lib/bundle/tablelayout.jar b/lib/bundle/tablelayout.jar
new file mode 100644
index 0000000..834fe9d
--- /dev/null
+++ b/lib/bundle/tablelayout.jar
Binary files differ
diff --git a/lib/jaxen-1.1-beta-8.jar b/lib/jaxen-1.1-beta-8.jar
new file mode 100644
index 0000000..6b007d9
--- /dev/null
+++ b/lib/jaxen-1.1-beta-8.jar
Binary files differ
diff --git a/lib/jmf-all/jmf.jar b/lib/jmf-all/jmf.jar
new file mode 100644
index 0000000..0e39053
--- /dev/null
+++ b/lib/jmf-all/jmf.jar
Binary files differ
diff --git a/lib/jmf-lin/jmf-native.jar b/lib/jmf-lin/jmf-native.jar
new file mode 100644
index 0000000..45352ab
--- /dev/null
+++ b/lib/jmf-lin/jmf-native.jar
Binary files differ
diff --git a/lib/jmf-lin/jmf.jar b/lib/jmf-lin/jmf.jar
new file mode 100644
index 0000000..049ef59
--- /dev/null
+++ b/lib/jmf-lin/jmf.jar
Binary files differ
diff --git a/lib/jmf-lin/libjmutil.so.jar b/lib/jmf-lin/libjmutil.so.jar
new file mode 100644
index 0000000..55eb9ec
--- /dev/null
+++ b/lib/jmf-lin/libjmutil.so.jar
Binary files differ
diff --git a/lib/jmf-sol/jmf-native.jar b/lib/jmf-sol/jmf-native.jar
new file mode 100644
index 0000000..86862f7
--- /dev/null
+++ b/lib/jmf-sol/jmf-native.jar
Binary files differ
diff --git a/lib/jmf-sol/jmf.jar b/lib/jmf-sol/jmf.jar
new file mode 100644
index 0000000..cdca61b
--- /dev/null
+++ b/lib/jmf-sol/jmf.jar
Binary files differ
diff --git a/lib/jmf-sol/libjmutil.so.jar b/lib/jmf-sol/libjmutil.so.jar
new file mode 100644
index 0000000..5c01ea5
--- /dev/null
+++ b/lib/jmf-sol/libjmutil.so.jar
Binary files differ
diff --git a/lib/jmf-win/jmf-native.jar b/lib/jmf-win/jmf-native.jar
new file mode 100644
index 0000000..2b0ea82
--- /dev/null
+++ b/lib/jmf-win/jmf-native.jar
Binary files differ
diff --git a/lib/jmf-win/jmf.jar b/lib/jmf-win/jmf.jar
new file mode 100644
index 0000000..556b508
--- /dev/null
+++ b/lib/jmf-win/jmf.jar
Binary files differ
diff --git a/lib/jmf-win/sound.jar b/lib/jmf-win/sound.jar
new file mode 100644
index 0000000..87625ec
--- /dev/null
+++ b/lib/jmf-win/sound.jar
Binary files differ
diff --git a/lib/junit.jar b/lib/junit.jar
new file mode 100644
index 0000000..674d71e
--- /dev/null
+++ b/lib/junit.jar
Binary files differ
diff --git a/lib/logging.properties b/lib/logging.properties
new file mode 100644
index 0000000..219e067
--- /dev/null
+++ b/lib/logging.properties
@@ -0,0 +1,54 @@
+############################################################
+# Default Logging Configuration File
+#
+# You can use a different file by specifying a filename
+# with the java.util.logging.config.file system property.
+# For example java -Djava.util.logging.config.file=myfile
+############################################################
+
+############################################################
+# Global properties
+############################################################
+
+# "handlers" specifies a comma separated list of log Handler
+# classes. These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# By default we only configure a ConsoleHandler, which will only
+# show messages at the INFO and above levels.
+handlers= java.util.logging.ConsoleHandler
+
+# To also add the FileHandler, use the following line instead.
+#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
+
+# Default global logging level.
+# This specifies which kinds of events are logged across
+# all loggers. For any given facility this global level
+# can be overriden by a facility specific level
+# Note that the ConsoleHandler also has a separate level
+# setting to limit messages printed to the console.
+.level= FINE
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+# default file output is in user's home directory.
+java.util.logging.FileHandler.pattern = %h/java%u.log
+java.util.logging.FileHandler.limit = 50000
+java.util.logging.FileHandler.count = 1
+java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
+
+# Limit the message that are printed on the console to FINE and above.
+java.util.logging.ConsoleHandler.level = FINEST
+java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
+
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages:
+com.xyz.foo.level = SEVERE
diff --git a/lib/moduleloader.jar b/lib/moduleloader.jar
new file mode 100644
index 0000000..f6e6239
--- /dev/null
+++ b/lib/moduleloader.jar
Binary files differ
diff --git a/lib/nist-sdp-1.0.jar b/lib/nist-sdp-1.0.jar
new file mode 100644
index 0000000..d273d49
--- /dev/null
+++ b/lib/nist-sdp-1.0.jar
Binary files differ
diff --git a/lib/nist-sip-1.2.jar b/lib/nist-sip-1.2.jar
new file mode 100644
index 0000000..4d2552a
--- /dev/null
+++ b/lib/nist-sip-1.2.jar
Binary files differ
diff --git a/lib/oscar.client.run.properties b/lib/oscar.client.run.properties
new file mode 100644
index 0000000..7e68add
--- /dev/null
+++ b/lib/oscar.client.run.properties
@@ -0,0 +1,67 @@
+#
+# Framework config properties.
+#
+org.osgi.framework.system.packages= org.osgi.framework; \
+ javax.swing;\
+ javax.swing.event;\
+ javax.swing.table;\
+ javax.swing.text; \
+ javax.accessibility; \
+ javax.swing.plaf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.swing.event; \
+ javax.swing.border; \
+ org.w3c.dom;\
+ org.xml.sax;\
+ javax.xml.parsers;\
+ org.jaxen; \
+ org.jaxen.dom; \
+ org.jaxen.saxpath; \
+ org.apache.xml.serializer;\
+ javax.xml.transform;\
+ javax.xml.transform.dom;\
+ javax.xml.transform.stream;\
+ javax.media;\
+ javax.media.format;\
+ javax.media.protocol;\
+ net.java.stun4j;\
+ net.java.stun4j.client;\
+ net.java.stun4j.StunAddress;\
+ net.java.stun4j.StunException;
+
+oscar.auto.start.1= \
+ file:lib/bundle/shell.jar \
+ file:lib/bundle/bundlerepository.jar \
+ file:lib/bundle/servicebinder.jar \
+ file:lib/bundle/tablelayout.jar
+
+oscar.auto.start.2= \
+ file:sc-bundles/util.jar
+
+oscar.auto.start.3= \
+ file:sc-bundles/configuration.jar \
+ file:sc-bundles/media.jar \
+ file:sc-bundles/netaddr.jar
+
+oscar.auto.start.4= \
+ file:sc-bundles/resources.jar \
+ file:sc-bundles/history.jar
+
+# Uncomment the following lines if you want to run the architect viewer
+# bundle.
+#oscar.auto.start.100= \
+# file:lib/bundle/architectureviewer1.1.jar
+
+#Specify the directory where oscar should deploy its bundles
+oscar.cache.profiledir=sip-communicator.bin
+
+
+oscar.startlevel.framework=100
+oscar.startlevel.bundle=100
+#
+# Bundle config properties.
+#
+#org.osgi.service.http.port=8080
+#osgi.shell.telnet=on
+#oscar.repository.url=file:/home/rickhall/projects/noscar/repository.xml
diff --git a/lib/oscar.jar b/lib/oscar.jar
new file mode 100644
index 0000000..f7fb491
--- /dev/null
+++ b/lib/oscar.jar
Binary files differ
diff --git a/lib/oscar.unit.test.properties b/lib/oscar.unit.test.properties
new file mode 100644
index 0000000..c3d582e
--- /dev/null
+++ b/lib/oscar.unit.test.properties
@@ -0,0 +1,79 @@
+#
+# Oscar configuration properties.
+# This file configures the OSCAR framework to run sip-communicator unit tests
+# and Service Implementation Compatibility Kits
+#
+org.osgi.framework.system.packages= org.osgi.framework; \
+ javax.swing; \
+ javax.swing.event; \
+ javax.swing.table; \
+ org.w3c.dom; \
+ org.xml.sax; \
+ javax.xml.parsers;\
+ org.jaxen; \
+ org.jaxen.dom; \
+ org.jaxen.saxpath; \
+ org.apache.xml.serializer;\
+ javax.xml.transform;\
+ javax.xml.transform.dom;\
+ javax.xml.transform.stream;\
+ javax.media;\
+ javax.media.format;\
+ javax.media.protocol;\
+ javax.sound.sampled;\
+ com.sun.media.protocol.javasound;\
+ com.sun.media.protocol.v4l;\
+ net.java.stun4j; \
+ net.java.stun4j.StunAddress;\
+ net.java.stun4j.StunException;\
+ net.java.stun4j.client;\
+ org.apache.tools.ant.taskdefs.optional.junit;
+
+
+#
+# In case you want testing to run using oscar's graphical ui then uncomment
+#
+# the following and copy/paste them after the shell.jar bundle
+# file:lib/bundle/shellgui.jar \
+# file:lib/bundle/shellplugin.jar \
+# file:lib/bundle/tablelayout.jar \
+#
+
+oscar.auto.start.1= \
+ file:lib/bundle/shell.jar \
+ file:lib/bundle/bundlerepository.jar \
+ file:lib/bundle/servicebinder.jar \
+ file:lib/bundle/junit.jar
+
+oscar.auto.start.2= \
+ file:sc-bundles/util.jar
+
+oscar.auto.start.3= \
+ file:sc-bundles/configuration.jar \
+ file:sc-bundles/media.jar \
+ file:sc-bundles/netaddr.jar
+
+oscar.auto.start.4= \
+ file:sc-bundles/protocol-sip.jar \
+ file:sc-bundles/resources.jar \
+ file:sc-bundles/history.jar
+
+oscar.auto.start.5= \
+ file:sc-bundles/slickless.jar \
+ file:sc-bundles/configuration-slick.jar \
+ file:sc-bundles/media-slick.jar \
+ file:sc-bundles/netaddr-slick.jar \
+ file:sc-bundles/resources-slick.jar \
+ file:sc-bundles/history-slick.jar
+
+
+oscar.auto.start.100= \
+ file:sc-bundles/slick-runner.jar
+
+#Specify the directory where oscar should deploy its bundles
+oscar.cache.profiledir=sip-communicator.utest.bin
+
+oscar.startlevel.framework=100
+oscar.startlevel.bundle=100
+
+oscar.embedded.execution=true
diff --git a/lib/osgi.jar b/lib/osgi.jar
new file mode 100644
index 0000000..0f9ca8a
--- /dev/null
+++ b/lib/osgi.jar
Binary files differ
diff --git a/lib/servicebinder.jar b/lib/servicebinder.jar
new file mode 100644
index 0000000..bfe2e40
--- /dev/null
+++ b/lib/servicebinder.jar
Binary files differ
diff --git a/lib/skinlf.jar b/lib/skinlf.jar
new file mode 100644
index 0000000..5486b0e
--- /dev/null
+++ b/lib/skinlf.jar
Binary files differ
diff --git a/src/net/java/sip/communicator/.cvsignore b/src/net/java/sip/communicator/.cvsignore
new file mode 100644
index 0000000..843c2e7
--- /dev/null
+++ b/src/net/java/sip/communicator/.cvsignore
@@ -0,0 +1 @@
+sick \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/configuration/.cvsignore b/src/net/java/sip/communicator/impl/configuration/.cvsignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/.cvsignore
diff --git a/src/net/java/sip/communicator/impl/configuration/Activator.java b/src/net/java/sip/communicator/impl/configuration/Activator.java
new file mode 100644
index 0000000..0ec34e2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/Activator.java
@@ -0,0 +1,74 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.configuration;
+
+import org.osgi.framework.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.util.Logger;
+import java.io.*;
+import net.java.sip.communicator.util.xml.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public class Activator
+ implements BundleActivator
+{
+ private Logger logger = Logger.getLogger(ConfigurationServiceImpl.class);
+ private ConfigurationServiceImpl impl = new ConfigurationServiceImpl();
+
+ /**
+ * Starts the configuration service
+ *
+ * @param bundleContext the BundleContext as provided from the osgi
+ * framework.
+ * @throws Exception if anything goes wrong
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ try
+ {
+ logger.logEntry();
+
+ bundleContext.registerService( ConfigurationService.class.getName(),
+ impl,
+ new java.util.Hashtable() );
+
+ logger.debug("Successfully registered " + getClass().getName());
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Causes the configuration service to store the properties object and
+ * unregisters the configuration servcice.
+ *
+ * @param bundlecontext BundleContext
+ * @throws Exception
+ * @todo Implement this org.osgi.framework.BundleActivator method
+ */
+ public void stop(BundleContext bundlecontext) throws Exception
+ {
+ try
+ {
+ logger.logEntry();
+
+
+
+ logger.info("The ConfigurationService stop method has been called.");
+ }
+ finally
+ {
+ logger.logEntry();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/configuration/ChangeEventDispatcher.java b/src/net/java/sip/communicator/impl/configuration/ChangeEventDispatcher.java
new file mode 100644
index 0000000..d0a116e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/ChangeEventDispatcher.java
@@ -0,0 +1,433 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.configuration;
+
+import net.java.sip.communicator.service.configuration.event.*;
+import java.util.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.util.xml.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+
+/**
+ * This is a utility class that can be used by objects that support constrained
+ * properties. You can use an instance of this class as a member field and
+ * delegate various work to it.
+ *
+ * @author Emil Ivov
+ */
+public class ChangeEventDispatcher
+{
+
+ /**
+ * All property change listeners registered so far.
+ */
+ private Vector propertyChangeListeners;
+
+ /**
+ * All listeners registered for vetoable change events.
+ */
+ private Vector vetoableChangeListeners;
+
+ /**
+ * Hashtable for managing property change listeners registered for specific
+ * properties. Maps property names to PropertyChangeSupport objects.
+ */
+ private Hashtable propertyChangeChildren;
+
+ /**
+ * Hashtable for managing vetoable change listeners registered for specific
+ * properties. Maps property names to PropertyChangeSupport objects.
+ */
+ private Hashtable vetoableChangeChildren;
+
+ /**
+ * The object to be provided as the "source" for any generated events.
+ */
+ private Object source;
+
+ /**
+ * Constructs a <code>VetoableChangeSupport</code> object.
+ *
+ * @param sourceObject The object to be given as the source for any events.
+ */
+ public ChangeEventDispatcher(Object sourceObject)
+ {
+ if (sourceObject == null)
+ {
+ throw new NullPointerException();
+ }
+ source = sourceObject;
+ }
+
+ /**
+ * Add a PropertyChangeListener to the listener list.
+ * The listener is registered for all properties.
+ *
+ * @param listener The PropertyChangeChangeListener to be added
+ */
+ public synchronized void addPropertyChangeListener(
+ PropertyChangeListener listener)
+ {
+ if (propertyChangeListeners == null)
+ {
+ propertyChangeListeners = new Vector();
+ }
+
+ propertyChangeListeners.addElement(listener);
+ }
+
+ /**
+ * Add a PropertyChangeListener for a specific property. The listener
+ * will be invoked only when a call on firePropertyChange names that
+ * specific property.
+ *
+ * @param propertyName The name of the property to listen on.
+ * @param listener The ConfigurationChangeListener to be added
+ */
+
+ public synchronized void addPropertyChangeListener(
+ String propertyName,
+ PropertyChangeListener listener)
+ {
+ if (propertyChangeChildren == null)
+ {
+ propertyChangeChildren = new Hashtable();
+ }
+ ChangeEventDispatcher child = (ChangeEventDispatcher) propertyChangeChildren.get(
+ propertyName);
+ if (child == null)
+ {
+ child = new ChangeEventDispatcher(source);
+ propertyChangeChildren.put(propertyName, child);
+ }
+ child.addPropertyChangeListener(listener);
+ }
+
+ /**
+ * Remove a PropertyChangeListener from the listener list.
+ * This removes a ConfigurationChangeListener that was registered
+ * for all properties.
+ *
+ * @param listener The PropertyChangeListener to be removed
+ */
+ public synchronized void removePropertyChangeListener(
+ PropertyChangeListener listener)
+ {
+
+ if (propertyChangeListeners == null)
+ {
+ return;
+ }
+ propertyChangeListeners.removeElement(listener);
+ }
+
+ /**
+ * Remove a PropertyChangeListener for a specific property.
+ *
+ * @param propertyName The name of the property that was listened on.
+ * @param listener The VetoableChangeListener to be removed
+ */
+ public synchronized void removePropertyChangeListener(
+ String propertyName,
+ PropertyChangeListener listener)
+ {
+ if (propertyChangeChildren == null)
+ {
+ return;
+ }
+ ChangeEventDispatcher child = (ChangeEventDispatcher)
+ propertyChangeChildren.get( propertyName );
+
+ if (child == null)
+ {
+ return;
+ }
+ child.removePropertyChangeListener(listener);
+ }
+
+ /**
+ * Add a VetoableChangeListener to the listener list.
+ * The listener is registered for all properties.
+ *
+ * @param listener The VetoableChangeListener to be added
+ */
+ public synchronized void addVetoableChangeListener(
+ VetoableChangeListener listener)
+ {
+ if (vetoableChangeListeners == null)
+ {
+ vetoableChangeListeners = new Vector();
+ }
+
+ vetoableChangeListeners.addElement(listener);
+ }
+
+ /**
+ * Remove a VetoableChangeListener from the listener list.
+ * This removes a VetoableChangeListener that was registered
+ * for all properties.
+ *
+ * @param listener The VetoableChangeListener to be removed
+ */
+ public synchronized void removeVetoableChangeListener(
+ VetoableChangeListener listener)
+ {
+
+ if (vetoableChangeListeners == null)
+ {
+ return;
+ }
+ vetoableChangeListeners.removeElement(listener);
+ }
+
+ /**
+ * Add a VetoableChangeListener for a specific property. The listener
+ * will be invoked only when a call on fireVetoableChange names that
+ * specific property.
+ *
+ * @param propertyName The name of the property to listen on.
+ * @param listener The ConfigurationChangeListener to be added
+ */
+
+ public synchronized void addVetoableChangeListener(
+ String propertyName,
+ VetoableChangeListener listener)
+ {
+ if (vetoableChangeChildren == null)
+ {
+ vetoableChangeChildren = new Hashtable();
+ }
+ ChangeEventDispatcher child = (ChangeEventDispatcher) vetoableChangeChildren.get(
+ propertyName);
+ if (child == null)
+ {
+ child = new ChangeEventDispatcher(source);
+ vetoableChangeChildren.put(propertyName, child);
+ }
+ child.addVetoableChangeListener(listener);
+ }
+
+ /**
+ * Remove a VetoableChangeListener for a specific property.
+ *
+ * @param propertyName The name of the property that was listened on.
+ * @param listener The VetoableChangeListener to be removed
+ */
+ public synchronized void removeVetoableChangeListener(
+ String propertyName,
+ VetoableChangeListener listener)
+ {
+ if (vetoableChangeChildren == null)
+ {
+ return;
+ }
+ ChangeEventDispatcher child = (ChangeEventDispatcher)
+ vetoableChangeChildren.get( propertyName );
+
+ if (child == null)
+ {
+ return;
+ }
+ child.removeVetoableChangeListener(listener);
+ }
+
+ /**
+ * Report a vetoable property update to any registered listeners. If
+ * no one vetos the change, then fire a new ConfigurationChangeEvent
+ * indicating that the change has been accepted. In the case of a
+ * PropertyVetoException, end eventdispatch and rethrow the eception
+ * <p>
+ * No event is fired if old and new are equal and non-null.
+ *
+ * @param propertyName The programmatic name of the property
+ * that is about to change..
+ * @param oldValue The old value of the property.
+ * @param newValue The new value of the property.
+ * @exception PropertyVetoException if the recipient wishes the property
+ * change to be rolled back.
+ */
+ public void fireVetoableChange(String propertyName,
+ Object oldValue, Object newValue) throws
+ PropertyVetoException
+ {
+ if (vetoableChangeListeners == null && vetoableChangeChildren == null)
+ {
+ return;
+ }
+
+ PropertyChangeEvent evt = new PropertyChangeEvent(source,
+ propertyName, oldValue, newValue);
+ fireVetoableChange(evt);
+ }
+
+ /**
+ * Fire a vetoable property update to any registered listeners. If
+ * anyone vetos the change, then the excption will be rethrown by this
+ * method.
+ * <p>
+ * No event is fired if old and new are equal and non-null.
+ *
+ * @param evt The PropertyChangeEvent to be fired.
+ * @exception PropertyVetoException if at least one of the recipients has
+ * vetoed the change.
+ */
+ public void fireVetoableChange(PropertyChangeEvent evt) throws
+ PropertyVetoException
+ {
+
+ Object oldValue = evt.getOldValue();
+ Object newValue = evt.getNewValue();
+ String propertyName = evt.getPropertyName();
+ if (oldValue != null && newValue != null && oldValue.equals(newValue))
+ {
+ return;
+ }
+
+ Vector targets = null;
+ ChangeEventDispatcher child = null;
+ synchronized (this)
+ {
+ if (vetoableChangeListeners != null)
+ {
+ targets = (Vector) vetoableChangeListeners.clone();
+ }
+ if (vetoableChangeChildren != null && propertyName != null)
+ {
+ child = (ChangeEventDispatcher)vetoableChangeChildren.get(propertyName);
+ }
+ }
+
+ if (vetoableChangeListeners != null)
+ {
+ for (int i = 0; i < targets.size(); i++)
+ {
+ VetoableChangeListener target =
+ (VetoableChangeListener) targets.elementAt(i);
+ //don't catch the exception - let it bounce to the caller.
+ target.vetoableChange(evt);
+ }
+ }
+
+ if (child != null)
+ {
+ child.fireVetoableChange(evt);
+ }
+ }
+
+
+ /**
+ * Report a bound property update to any registered listeners.
+ * No event is fired if old and new are equal and non-null.
+ *
+ * @param propertyName The programmatic name of the property
+ * that was changed.
+ * @param oldValue The old value of the property.
+ * @param newValue The new value of the property.
+ */
+ public void firePropertyChange(String propertyName,
+ Object oldValue, Object newValue)
+ {
+ if (oldValue != null && newValue != null && oldValue.equals(newValue))
+ {
+ return;
+ }
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ oldValue, newValue));
+ }
+
+ /**
+ * Fire an existing PropertyChangeEvent to any registered listeners.
+ * No event is fired if the given event's old and new values are
+ * equal and non-null.
+ * @param evt The PropertyChangeEvent object.
+ */
+ public void firePropertyChange(PropertyChangeEvent evt)
+ {
+ Object oldValue = evt.getOldValue();
+ Object newValue = evt.getNewValue();
+ String propertyName = evt.getPropertyName();
+ if (oldValue != null && newValue != null && oldValue.equals(newValue))
+ {
+ return;
+ }
+
+ if (propertyChangeListeners != null)
+ {
+ Iterator iterator = propertyChangeListeners.iterator();
+ while (iterator.hasNext())
+ {
+ PropertyChangeListener target =
+ (PropertyChangeListener) iterator.next();
+ target.propertyChange(evt);
+ }
+ }
+
+ if (propertyChangeChildren != null && propertyName != null)
+ {
+ ChangeEventDispatcher child = null;
+ child = (ChangeEventDispatcher) propertyChangeChildren.get(propertyName);
+ if (child != null)
+ {
+ child.firePropertyChange(evt);
+ }
+ }
+ }
+
+ /**
+ * Check if there are any listeners for a specific property. (Generic
+ * listeners count as well)
+ *
+ * @param propertyName the property name.
+ * @return true if there are one or more listeners for the given property
+ */
+ public synchronized boolean hasPropertyChangeListeners(String propertyName)
+ {
+ if(propertyChangeListeners != null && !propertyChangeListeners.isEmpty())
+ {
+ // there is a generic listener
+ return true;
+ }
+ if (propertyChangeChildren != null)
+ {
+ ChangeEventDispatcher child = (ChangeEventDispatcher) propertyChangeChildren.get(
+ propertyName);
+ if (child != null && child.propertyChangeListeners != null)
+ {
+ return!child.propertyChangeListeners.isEmpty();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if there are any vetoable change listeners for a specific property.
+ * (Generic vetoable change listeners count as well)
+ *
+ * @param propertyName the property name.
+ * @return true if there are one or more listeners for the given property
+ */
+ public synchronized boolean hasVetoableChangeListeners(String propertyName)
+ {
+ if(vetoableChangeListeners != null && !vetoableChangeListeners.isEmpty())
+ {
+ // there is a generic listener
+ return true;
+ }
+ if (vetoableChangeChildren != null)
+ {
+ ChangeEventDispatcher child = (ChangeEventDispatcher)
+ vetoableChangeChildren.get(propertyName);
+
+ if (child != null && child.vetoableChangeListeners != null)
+ {
+ return!child.vetoableChangeListeners.isEmpty();
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java b/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java
new file mode 100644
index 0000000..2707da1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java
@@ -0,0 +1,846 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.configuration;
+
+import java.io.*;
+import java.util.*;
+import javax.xml.parsers.*;
+
+import org.w3c.dom.*;
+import org.xml.sax.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.configuration.event.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.xml.*;
+
+
+
+/**
+ * A straight forward implementation of the ConfigurationService using an xml
+ * file for storing properties. Currently only String properties are
+ * meaningfully saved (we should probably consider how and whether we should
+ * take care of the rest).
+ *
+ * @author Emil Ivov
+ * @author Damian Minkov
+ */
+public class ConfigurationServiceImpl
+ implements ConfigurationService
+{
+ private Logger logger = Logger.getLogger(ConfigurationServiceImpl.class);
+
+ /**
+ * The XML Document containing the configuration file this service loaded.
+ */
+ private Document propertiesDocument = null;
+
+ /** Name of the xml attribute containing property values */
+ private static final String ATTRIBUTE_VALUE = "value";
+
+ /**
+ * Name of the xml attribute indicating that a property is to be resolved
+ * in the system properties
+ */
+ private static final String SYSTEM_ATTRIBUTE_NAME = "system";
+
+ /** The value of the Name of the xml attribute containing property values */
+ private static final String SYSTEM_ATTRIBUTE_TRUE = "true";
+
+ /**
+ * The name of the system property that stores the name of the configuration
+ * file.
+ */
+ private static final String FILE_NAME_PROPERTY =
+ "net.java.sip.communicator.PROPERTIES_FILE_NAME";
+
+ /**
+ * Our event dispatcher.
+ */
+ private ChangeEventDispatcher changeEventDispatcher =
+ new ChangeEventDispatcher(this);
+
+ /**
+ * The list of properties currently registered in the configuration service.
+ */
+ private Map properties = new Hashtable();
+
+ /**
+ * Contains the properties that were initially loaded from the configuration
+ * file or (if the properties have been modified and saved since initially
+ * loaded) those that were last written to the file.We use the property so
+ * that we could determine which properties are new and do not have a
+ * corresponding node in the XMLDocument object.
+ */
+ private Map fileExtractedProperties = new Hashtable();
+
+ /**
+ * Sets the property with the specified name to the specified value. Calling
+ * this method would first trigger a PropertyChangeEvent that will
+ * be dispatched to all VetoableChangeListeners. In case no complaints
+ * (PropertyVetoException) have been received, the property will be actually
+ * changed and a PropertyChangeEvent will be dispatched.
+ * <p>
+ * @param propertyName String
+ * @param property Object
+ * @throws PropertyVetoException in case the changed has been refused by
+ * at least one propertychange listener.
+ */
+ public void setProperty(String propertyName, Object property)
+ throws PropertyVetoException
+ {
+ setProperty(propertyName, property, false);
+ }
+
+ /**
+ * Sets the property with the specified name to the specified. Calling
+ * this method would first trigger a PropertyChangeEvent that will
+ * be dispatched to all VetoableChangeListeners. In case no complaints
+ * (PropertyVetoException) have been received, the property will be actually
+ * changed and a PropertyChangeEvent will be dispatched. This method also
+ * allows the caller to specify whether or not the specified property is a
+ * system one.
+ * <p>
+ * @param propertyName the name of the property to change.
+ * @param property the new value of the specified property.
+ * @param isSystem specifies whether or not the property being is a System
+ * property and should be resolved against the system
+ * property set. If the property has previously been
+ * specified as system then this value is inteernally forced
+ * to true.
+ * @throws PropertyVetoException in case the changed has been refused by
+ * at least one propertychange listener.
+ */
+ public void setProperty(String propertyName, Object property,
+ boolean isSystem) throws PropertyVetoException
+ {
+ try{
+ logger.logEntry();
+
+ Object oldValue = getProperty(propertyName);
+ //first check whether the change is ok with everyone
+ if (changeEventDispatcher.hasVetoableChangeListeners(propertyName))
+ changeEventDispatcher.fireVetoableChange(
+ propertyName, oldValue, property);
+
+ //no exception was thrown - lets change the property and fire a
+ //change event
+
+ logger.trace(propertyName+"( oldValue="+oldValue
+ +", newValue=" + property+".");
+
+ //once set system, a property remains system event if the user
+ //specified sth else
+
+ if( isSystem(propertyName) )
+ isSystem = true;
+
+ if (property == null){
+ properties.remove(propertyName);
+
+ if(isSystem){
+ //we can't remove or nullset a sys prop so let's "empty" it.
+ System.setProperty(propertyName, "");
+ }
+ }
+ else{
+ if(isSystem){
+ //in case this is a system property, we must only store it
+ //in the System property set and keep only a ref locally.
+ System.setProperty(propertyName, property.toString());
+ properties.put(propertyName,
+ new PropertyReference(propertyName));
+ }
+ else{
+ properties.put(propertyName, property);
+ }
+ }
+ if (changeEventDispatcher.hasPropertyChangeListeners(propertyName))
+ changeEventDispatcher.firePropertyChange(
+ propertyName, oldValue, property);
+ }
+ finally
+ {
+ logger.logExit();
+ }
+
+ }
+
+ /**
+ * Returns the value of the property with the specified name or null if no
+ * such property exists.
+ * @param propertyName the name of the property that is being queried.
+ * @return the value of the property with the specified name.
+ */
+ public Object getProperty(String propertyName)
+ {
+ Object value = properties.get(propertyName);
+
+ //if this is a property reference make sure we return the referenced
+ //value and not the reference itself
+ if(value instanceof PropertyReference)
+ return ((PropertyReference)value).getValue();
+ else
+ return value;
+ }
+
+ /**
+ * Adds a PropertyChangeListener to the listener list.
+ *
+ * @param listener the PropertyChangeListener to be added
+ */
+ public void addPropertyChangeListener(PropertyChangeListener listener)
+ {
+ changeEventDispatcher.addPropertyChangeListener(listener);
+ }
+
+ /**
+ * Removes a PropertyChangeListener from the listener list.
+ *
+ * @param listener the PropertyChangeListener to be removed
+ */
+ public void removePropertyChangeListener(PropertyChangeListener listener)
+ {
+ changeEventDispatcher.removePropertyChangeListener(listener);
+ }
+
+ /**
+ * Adds a PropertyChangeListener to the listener list for a specific
+ * property.
+ *
+ * @param propertyName one of the property names listed above
+ * @param listener the PropertyChangeListener to be added
+ */
+ public void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener)
+ {
+ changeEventDispatcher.
+ addPropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Removes a PropertyChangeListener from the listener list for a specific
+ * property.
+ *
+ * @param propertyName a valid property name
+ * @param listener the PropertyChangeListener to be removed
+ */
+ public void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener)
+ {
+ changeEventDispatcher.
+ removePropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Adds a VetoableChangeListener to the listener list.
+ *
+ * @param listener the VetoableChangeListener to be added
+ */
+ public void addVetoableChangeListener(VetoableChangeListener listener)
+ {
+ changeEventDispatcher.addVetoableChangeListener(listener);
+ }
+
+ /**
+ * Removes a VetoableChangeListener from the listener list.
+ *
+ * @param listener the VetoableChangeListener to be removed
+ */
+ public void removeVetoableChangeListener(VetoableChangeListener listener)
+ {
+ changeEventDispatcher.removeVetoableChangeListener(listener);
+ }
+
+ /**
+ * Adds a VetoableChangeListener to the listener list for a specific
+ * property.
+ *
+ * @param propertyName one of the property names listed above
+ * @param listener the VetoableChangeListener to be added
+ */
+ public void addVetoableChangeListener(String propertyName,
+ VetoableChangeListener listener)
+ {
+ changeEventDispatcher.addVetoableChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Removes a VetoableChangeListener from the listener list for a specific
+ * property.
+ *
+ * @param propertyName a valid property name
+ * @param listener the VetoableChangeListener to be removed
+ */
+ public void removeVetoableChangeListener(String propertyName,
+ VetoableChangeListener listener)
+ {
+ changeEventDispatcher.removeVetoableChangeListener(propertyName,
+ listener);
+ }
+
+ /**
+ * Initializes the configuration service impl and makes it load an initial
+ * configuration from the conf file.
+ */
+ void start()
+ {
+ try
+ {
+ reloadConfiguration();
+ }
+ catch (XMLException ex)
+ {
+ logger.error("Failed to parse the configuration file.", ex);
+ }
+ catch (IOException ex)
+ {
+ logger.error("Failed to load the configuration file", ex);
+ }
+ }
+
+ public void reloadConfiguration()
+ throws IOException, XMLException
+ {
+ properties = new Hashtable();
+ fileExtractedProperties =
+ loadConfiguration(getConfigurationFile());
+ this.properties.putAll(fileExtractedProperties);
+ }
+
+ /**
+ * Loads the contents of the specified configuration file into the local
+ * properties object.
+ * @param file a reference to the configuration file to load.
+ * @return a hashtable containing all properties extracted from the
+ * specified file.
+ *
+ * @throws IOException if the specified file does not exist
+ * @throws XMLException if there is a problem with the file syntax.
+ */
+ Map loadConfiguration(File file)
+ throws IOException, XMLException
+ {
+ try
+ {
+ logger.logEntry();
+
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Map properties = new Hashtable();
+
+ propertiesDocument = builder.parse(file);
+
+ Node root = propertiesDocument.getFirstChild();
+
+ Node currentNode = null;
+ NodeList children = root.getChildNodes();
+ for(int i = 0; i < children.getLength(); i++)
+ {
+ currentNode = children.item(i);
+
+ if(currentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ StringBuffer propertyNameBuff = new StringBuffer();
+ propertyNameBuff.append(currentNode.getNodeName());
+ loadNode(currentNode, propertyNameBuff, properties);
+ }
+ }
+
+ return properties;
+ }
+ catch(SAXException ex)
+ {
+ logger.error("Error parsing configuration file", ex);
+ throw new XMLException(ex.getMessage(), ex);
+ }
+ catch(ParserConfigurationException ex)
+ {
+ //it is not highly probable that this might happen - so lets just
+ //log it.
+ logger.error("Error finding configuration for default parsers", ex);
+ return new Hashtable();
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ public void storeConfiguration()
+ throws IOException
+ {
+ storeConfiguration(getConfigurationFile());
+
+ }
+
+ /**
+ * Stores local properties in the specified configuration file.
+ * @param file a reference to the configuration file where properties should
+ * be stored.
+ * @throws IOException if there was a problem writing to the specified file.
+ */
+ private void storeConfiguration(File file)
+ throws IOException
+ {
+ try
+ {
+ logger.logEntry();
+
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+
+ //resolve the properties that were initially in the file - back to
+ //the document.
+
+ Node root = propertiesDocument.getFirstChild();
+
+ Node currentNode = null;
+ NodeList children = root.getChildNodes();
+ for(int i = 0; i < children.getLength(); i++)
+ {
+ currentNode = children.item(i);
+
+ if(currentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ StringBuffer propertyNameBuff = new StringBuffer();
+ propertyNameBuff.append(currentNode.getNodeName());
+ updateNode(currentNode, propertyNameBuff, properties);
+ }
+ }
+
+ //create in the document the properties that were added by other
+ //bundles after the initial property load.
+
+ Map newlyAddedProperties = cloneProperties();
+
+ //remove those that were originally there;
+ Iterator propNames = fileExtractedProperties.keySet().iterator();
+ while(propNames.hasNext())
+ newlyAddedProperties.remove(propNames.next());
+
+ this.processNewProperties(propertiesDocument,
+ newlyAddedProperties);
+
+
+ //write the file.
+ XMLConfUtils.writeXML(propertiesDocument, getConfigurationFile());
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Loads the contents of the specified node and its children into the local
+ * properties. Any nodes marked as "system" will also be resolved in the
+ * system properties.
+ * @param node the root node that we shold load together with its children
+ * @param propertyNameBuff a StringBuffer containing the prefix describing
+ * the route to the specified node including its one name
+ * @param properties the dictionary object where all properties extracted
+ * from this node and its children should be recorded.
+ */
+ private void loadNode(Node node,
+ StringBuffer propertyNameBuff,
+ Map properties)
+ {
+ Node currentNode = null;
+ NodeList children = node.getChildNodes();
+ for(int i = 0; i < children.getLength(); i++)
+ {
+ currentNode = children.item(i);
+
+ if(currentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ StringBuffer newPropBuff =
+ new StringBuffer(propertyNameBuff
+ + "." +currentNode.getNodeName());
+ String value = XMLConfUtils.getAttribute(
+ currentNode, ATTRIBUTE_VALUE);
+
+ String propertyType =
+ XMLConfUtils.getAttribute(currentNode, SYSTEM_ATTRIBUTE_NAME);
+
+ // the value attr is present we must handle the desired property
+ if(value != null)
+ {
+
+ //if the property is marked as "system", we should resolve
+ //it against the system properties and only store a
+ //reference locally. this is normally done for properties
+ //that are supposed to configure underlying libraries.
+ if(propertyType != null
+ && propertyType.equals(SYSTEM_ATTRIBUTE_TRUE))
+ {
+ properties.put(
+ newPropBuff.toString(),
+ new PropertyReference(newPropBuff.toString()));
+ System.setProperty(newPropBuff.toString(), value);
+ }
+ else
+ {
+ properties.put(newPropBuff.toString(), value);
+ }
+ }
+
+ //load child nodes
+ loadNode(currentNode, newPropBuff, properties);
+
+ }
+ }
+ }
+
+ /**
+ * Updates the value of the specified node and its children to reflect those
+ * in the properties file. Nodes marked as "system" will be updated from
+ * the specified properties object and not from the system properties since
+ * if any intentional change (through a configuration form) has occurred
+ * it will have been made there.
+ *
+ * @param node the root node that we shold update together with its children
+ * @param propertyNameBuff a StringBuffer containing the prefix describing
+ * the dot separated route to the specified node including its one name
+ * @param properties the dictionary object where the up to date values of
+ * the node should be queried.
+ */
+ private void updateNode(Node node,
+ StringBuffer propertyNameBuff,
+ Map properties)
+ {
+ Node currentNode = null;
+ NodeList children = node.getChildNodes();
+ for(int i = 0; i < children.getLength(); i++)
+ {
+ currentNode = children.item(i);
+
+ if(currentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ StringBuffer newPropBuff =
+ new StringBuffer(propertyNameBuff
+ + "." +currentNode.getNodeName());
+
+ Attr attr =
+ ((Element)currentNode).getAttributeNode(ATTRIBUTE_VALUE);
+
+ if(attr != null)
+ {
+ //update the corresponding node
+ Object value = properties.get(newPropBuff.toString());
+ boolean isSystem = value instanceof PropertyReference;
+ String prop = isSystem
+ ?((PropertyReference)value).getValue().toString()
+ :value.toString();
+
+ attr.setNodeValue(prop);
+
+ //in case the property has changed to system since the last
+ //load - update the conf file accordingly.
+ if(isSystem)
+ ((Element)currentNode).setAttribute(
+ SYSTEM_ATTRIBUTE_NAME, SYSTEM_ATTRIBUTE_TRUE);
+ else
+ ((Element)currentNode).removeAttribute(
+ SYSTEM_ATTRIBUTE_NAME);
+
+ }
+
+ //update child nodes
+ updateNode(currentNode, newPropBuff, properties);
+ }
+ }
+ }
+
+ /**
+ * Returns a reference to the configuration file that the service should
+ * load. The method would try to load a file with the name
+ * sip-communicator.xml unless a different one is specified in the system
+ * property net.java.sip.communicator.PROPERTIES_FILE_NAME . The method
+ * would first try to load the file from the current directory if it exists
+ * this is not the case a load would be attempted from the
+ * $HOME/.sip-communicator directory. In case it was not found there either
+ * we'll look for it in all locations currently present in the $CLASSPATH.
+ * In case we find it in there we will copy it to the
+ * $HOME/.sip-communicator directory in case it was in a jar archive and
+ * return the reference to the newly created file. In case the file is
+ * to be found noweher - a new empty file in the user home directory and
+ * returns a link to that one.
+ *
+ *
+ * @return the configuration the sip-
+ */
+ File getConfigurationFile()
+ {
+ try
+ {
+ logger.logEntry();
+
+ //see whether we have a user specified name for the conf file
+ String pFileName = getSystemProperty(
+ FILE_NAME_PROPERTY);
+ if (pFileName == null)
+ {
+ pFileName = "sip-communicator.xml";
+ }
+
+ // try to open the file in current directory
+ File configFileInCurrentDir = new File(pFileName);
+ if (configFileInCurrentDir.exists())
+ {
+ logger.debug("Using config file in current dir: "
+ + configFileInCurrentDir.getCanonicalPath());
+ return configFileInCurrentDir;
+ }
+
+ // we didn't find it in ".", try the user.home directory
+ File configDir = new File(getSystemProperty("user.home") +
+ File.separator +
+ ".sip-communicator");
+
+ File configFileInUserHomeDir =
+ new File(configDir, pFileName);
+
+ if (configFileInUserHomeDir.exists())
+ {
+ logger.debug("Using config file in $HOME/.sip-communicator: "
+ + configFileInCurrentDir.getCanonicalPath());
+ return configFileInUserHomeDir;
+ }
+
+ // If we are in a jar - copy config file from jar to user home.
+ logger.trace("Copying config file.");
+
+ configDir.mkdirs();
+ InputStream in = getClass().getClassLoader().
+ getResourceAsStream(pFileName);
+
+ //Return an empty file if there wasn't any in the jar
+ //null check report from John J. Barton - IBM
+ if (in == null)
+ {
+ configFileInUserHomeDir.createNewFile();
+ logger.debug("Created an empty file in $HOME: "
+ + configFileInCurrentDir.getCanonicalPath());
+ return configFileInUserHomeDir;
+ }
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(in));
+
+ PrintWriter writer = new PrintWriter(new FileWriter(
+ configFileInUserHomeDir));
+
+ String line = null;
+ logger.debug("Copying properties file:");
+ while ( (line = reader.readLine()) != null)
+ {
+ writer.println(line);
+ logger.debug(line);
+ }
+ writer.flush();
+ return configFileInUserHomeDir;
+ }
+ catch (IOException ex)
+ {
+ logger.error("Error creating config file", ex);
+ return null;
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Creates new entries in the xml <code>doc</code> for every element in the
+ * <code>newProperties</code> table.
+ *
+ * @param doc the XML <code>Document</code> where the new entries should be
+ * created
+ * @param newProperties the table containing the properties that are to be
+ * in troduced in the document.
+ */
+ private void processNewProperties(Document doc,
+ Map newProperties)
+ {
+ Iterator propNames = newProperties.keySet().iterator();
+ while(propNames.hasNext())
+ {
+ String key = (String)propNames.next();
+ Object value = newProperties.get(key);
+ boolean isSystem = value instanceof PropertyReference;
+ value = isSystem
+ ?((PropertyReference)value).getValue()
+ :value;
+ processNewProperty(doc, key, value.toString(), isSystem);
+ }
+ }
+
+ /**
+ * Creates an entry in the xml <code>doc</code> for the specified key value
+ * pair.
+ * @param doc the XML <code>document</code> to update.
+ * @param key the value of the <code>name</code> attribute for the new entry
+ * @param value the value of the <code>value</code> attribue for the new
+ * @param isSystem specifies whether this is a system property (system
+ * attribute will be set to true).
+ * entry.
+ */
+ private void processNewProperty(Document doc,
+ String key,
+ String value,
+ boolean isSystem)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(key, ".");
+ String[] toks = new String[tokenizer.countTokens()];
+ int i = 0;
+ while(tokenizer.hasMoreTokens())
+ toks[i++] = tokenizer.nextToken();
+
+ String[] chain = new String[toks.length - 1];
+ for (int j = 0; j < chain.length; j++)
+ {
+ chain[j] = toks[j];
+ }
+
+ String nodeName = toks[toks.length - 1];
+
+ Element parent = XMLConfUtils.createLastPathComponent(doc, chain);
+ Element newNode = XMLConfUtils.findChild(parent, nodeName);
+ if (newNode == null)
+ {
+ newNode = doc.createElement(nodeName);
+ parent.appendChild(newNode);
+ }
+ newNode.setAttribute("value", value);
+
+ if(isSystem)
+ newNode.setAttribute(SYSTEM_ATTRIBUTE_NAME, SYSTEM_ATTRIBUTE_TRUE);
+
+ }
+
+
+ /**
+ * Returns the value of the specified java system property. In case the
+ * value was a zero length String or one that only contained whitespaces,
+ * null is returned. This method is for internal use only. Users of the
+ * configuration service are to use the getProperty() or getString() methods
+ * which would automatically determine whether a property is system or not.
+ * @param propertyName the name of the property whose value we need.
+ * @return the value of the property with name propertyName or null if
+ * the value had length 0 or only contained spaces tabs or new lines.
+ */
+ private static String getSystemProperty(String propertyName)
+ {
+ String retval = System.getProperty(propertyName);
+ if (retval == null){
+ return retval;
+ }
+
+ if (retval.trim().length() == 0){
+ return null;
+ }
+ return retval;
+ }
+
+ /**
+ * Returns the String value of the specified property (minus all
+ * encompasssing whitespaces)and null in case no property value was mapped
+ * against the specified propertyName, or in case the returned property
+ * string had zero length or contained whitespaces only.
+ *
+ * @param propertyName the name of the property that is being queried.
+ * @return the result of calling the property's toString method and null in
+ * case there was no vlaue mapped against the specified
+ * <code>propertyName</code>, or the returned string had zero length or
+ * contained whitespaces only.
+ */
+ public String getString(String propertyName)
+ {
+ Object propValue = getProperty(propertyName);
+ if (propValue == null)
+ return null;
+
+ String propStrValue = propValue.toString().trim();
+
+ return propStrValue.length() > 0
+ ? propStrValue
+ : null;
+ }
+
+ /**
+ * We use property references when we'd like to store system properties.
+ * Simply storing System properties in our properties Map would not be
+ * enough since it will lead to mismatching values for the same property in
+ * the System property set and in our local set of properties. Storing them
+ * only in the System property set OTOH is a bit clumsy since it obliges
+ * bundles to use to different configuration property sources. For that
+ * reason, every time we get handed a property labeled as System, in stead
+ * of storing its actual value in the local property set we store a
+ * PropertyReference instance that will retrive it from the system
+ * properties when necessary.
+ */
+ private class PropertyReference
+ {
+ private String propertyName = null;
+
+ PropertyReference(String propertyName)
+ {
+ this.propertyName = propertyName;
+ }
+
+ /**
+ * Return the actual value of the property as recorded in the System
+ * properties.
+ * @return the valued of the property as recorded in the System props.
+ */
+ public Object getValue()
+ {
+ return System.getProperty(propertyName);
+ }
+ }
+
+ /**
+ * Returns a copy of the Map containing all configuration properties
+ * @return a Map clone of the current configuration property set.
+ */
+ private Map cloneProperties()
+ {
+ //at the time I'm writing this method we're implementing the
+ //configuraiton service through the use of a hashtable. this may very
+ //well change one day so let's not be overy assumptious (can you
+ //actually say that?)
+ if(properties instanceof Hashtable)
+ return (Map)((Hashtable)properties).clone();
+ if(properties instanceof HashMap)
+ return (Map)((HashMap)properties).clone();
+ if(properties instanceof TreeMap)
+ return (Map)((TreeMap)properties).clone();
+
+ //well you can't say that I didn't try!!!
+
+ return new Hashtable(properties);
+ }
+
+ /**
+ * Determines whether the property with the specified
+ * <code>propertyName</code> has been previously declared as System
+ *
+ * @param propertyName the name of the property to verify
+ * @return true if someone at some point specified that property to be
+ * system. (This could have been either through a call to
+ * setProperty(string, true)) or by setting the system attribute in the
+ * xml conf file to true.
+ */
+ private boolean isSystem(String propertyName)
+ {
+ return properties.containsKey(propertyName)
+ && properties.get(propertyName) instanceof PropertyReference;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/configuration/configuration.manifest.mf b/src/net/java/sip/communicator/impl/configuration/configuration.manifest.mf
new file mode 100644
index 0000000..8d8be37
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/configuration.manifest.mf
@@ -0,0 +1,18 @@
+Bundle-Activator: net.java.sip.communicator.impl.configuration.Activator
+Bundle-Name: Configuration Service Implementation
+Bundle-Description: A bundle that offers configuration utilities
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.osgi.framework,
+ org.apache.xml.serializer,
+ org.xml.sax,
+ org.w3c.dom,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
+ javax.xml.parsers,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.xml,
+Export-Package: net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.configuration.event,
+ net.java.sip.communicator.impl.configuration.xml,
diff --git a/src/net/java/sip/communicator/impl/configuration/res/configuration.manifest.mf b/src/net/java/sip/communicator/impl/configuration/res/configuration.manifest.mf
new file mode 100644
index 0000000..85f6b4a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/res/configuration.manifest.mf
@@ -0,0 +1,7 @@
+Bundle-Activator: net.java.sip.communicator.impl.configuration.Activator
+Export-Package: net.java.sip.communicator.service.configuration;net.java.sip.communicator.service.configuration.event;
+Import-Package: net.java.sip.communicator.service.configuration;junit;junit.framework;junit.swingui;junit.textui;junit.awtui;junit.extensions;org.osgi.framework
+Bundle-Name: Configuration Service Implementation
+Bundle-Description: A bundle that offers configuration utilities
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1 \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/configuration/xml/XMLConfUtils.java b/src/net/java/sip/communicator/impl/configuration/xml/XMLConfUtils.java
new file mode 100644
index 0000000..1d6d85a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/xml/XMLConfUtils.java
@@ -0,0 +1,83 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.configuration.xml;
+
+import org.w3c.dom.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.xml.*;
+
+
+
+/**
+ * Common XML Tasks.
+ *
+ * @author Damian Minkov
+ * @author Emil Ivov
+ */
+public class XMLConfUtils extends XMLUtils
+{
+ private static Logger logger = Logger.getLogger(XMLConfUtils.class);
+
+ /**
+ * Returns the element which is at the end of the specified
+ * String chain. <great...grandparent>...<grandparent>.<parent>.<child>
+ * @param parent the xml element that is the parent of the root of this
+ * chain.
+ * @param chain a String array containing the names of all the child's
+ * parent nodes.
+ * @return the node represented by the specified chain
+ */
+ public static Element getChildElementByChain(Element parent,
+ String[] chain,
+ boolean create)
+ {
+ if(chain == null)
+ return null;
+ Element e = parent;
+ for(int i=0; i<chain.length; i++)
+ {
+ if(e == null)
+ return null;
+ e = findChild(e, chain[i]);
+ }
+ return e;
+ }
+
+ /**
+ * Creates (only if necessary) and returns the element which is at the end
+ * of the specified path.
+ * @param doc the target document where the specified path should be created
+ * @param path a dot separated string indicating the path to be created
+ * @return the component at the end of the newly created path.
+ */
+ public static Element createLastPathComponent(Document doc, String[] path)
+ {
+ Element parent = (Element)doc.getFirstChild();
+ if( path == null
+ || parent == null
+ || doc == null)
+ throw new IllegalArgumentException(
+ "Document parent and path must not be null");
+
+ Element e = parent;
+ for(int i=0; i < path.length; i++)
+ {
+ Element newEl = findChild(e, path[i]);
+ if(newEl == null)
+ {
+ newEl = doc.createElement(path[i]);
+ e.appendChild(newEl);
+ }
+ e = newEl;
+ }
+ return e;
+ }
+
+
+
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/Activator.java b/src/net/java/sip/communicator/impl/gui/Activator.java
new file mode 100644
index 0000000..a47212c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/Activator.java
@@ -0,0 +1,45 @@
+package net.java.sip.communicator.impl.gui;
+
+import net.java.sip.communicator.service.gui.UIService;
+import net.java.sip.communicator.util.Logger;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+
+public class Activator implements BundleActivator
+{
+
+ private Logger logger = Logger.getLogger(Activator.class.getName());
+
+ private UIService uiService = null;
+
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ try
+ {
+ logger.logEntry();
+
+ //Create the ui service
+ this.uiService =
+ new UIServiceImpl();
+
+ logger.info("UI Service...[ STARTED ]");
+
+ bundleContext.registerService(
+ UIService.class.getName(), this.uiService, null);
+
+ logger.info("UI Service ...[REGISTERED]");
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ public void stop(BundleContext bundleContext) throws Exception
+ {
+ logger.info("UI Service ...[STOPED]");
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java
new file mode 100644
index 0000000..c160070
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java
@@ -0,0 +1,63 @@
+package net.java.sip.communicator.impl.gui;
+
+import net.java.sip.communicator.service.gui.UIService;
+import net.java.sip.communicator.service.protocol.Call;
+import net.java.sip.communicator.service.protocol.ProtocolProviderService;
+
+public class UIServiceImpl implements UIService {
+
+
+ public void registerProvider(ProtocolProviderService provider) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setVisible(boolean visible) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Call[] getActiveCalls() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getUiLibName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String[] getSupportedUiLibNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void addMenuItem(String parent, Object menuItem)
+ throws ClassCastException, IllegalArgumentException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void addComponent(Object component, String constraint)
+ throws ClassCastException, IllegalArgumentException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void addUserActionListener() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void requestAuthentication(String realm, String userName,
+ char[] password) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public String getAuthenticationUserName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/gui.manifest.mf b/src/net/java/sip/communicator/impl/gui/gui.manifest.mf
new file mode 100644
index 0000000..7d97775
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/gui.manifest.mf
@@ -0,0 +1,6 @@
+Bundle-Activator: net.java.sip.communicator.impl.gui.Activator
+Bundle-Name: Resources Management Service Provider
+Bundle-Description: A bundle that implements the resource management package.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Export-Package: net.java.sip.communicator.gui,
diff --git a/src/net/java/sip/communicator/impl/gui/main/CallList.java b/src/net/java/sip/communicator/impl/gui/main/CallList.java
new file mode 100755
index 0000000..9ab53a4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/CallList.java
@@ -0,0 +1,19 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.util.Vector;
+
+import javax.swing.JList;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The call list.
+ * TODO: to be removed.
+ */
+
+public class CallList extends JList {
+
+ public CallList(Vector data){
+ super(data);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/CallPanel.java b/src/net/java/sip/communicator/impl/gui/main/CallPanel.java
new file mode 100644
index 0000000..e4cf405
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/CallPanel.java
@@ -0,0 +1,54 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Image;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComboBox;
+import javax.swing.JPanel;
+
+import net.java.sip.communicator.impl.gui.main.customcontrols.SIPCommButton;
+
+public class CallPanel extends JPanel{
+
+ private Image callButtonIcon = LookAndFeelConstants.CALL_BUTTON_ICON;
+ private Image hangupButtonIcon = LookAndFeelConstants.HANG_UP_BUTTON_ICON;
+ private Image callButtonBG = LookAndFeelConstants.CALL_BUTTON_BG;
+ private Image callButtonRolloverBG = LookAndFeelConstants.CALL_ROLLOVER_BUTTON_BG;
+ private Image hangupButtonBG = LookAndFeelConstants.HANGUP_BUTTON_BG;
+ private Image hangupButtonRolloverBG = LookAndFeelConstants.HANGUP_ROLLOVER_BUTTON_BG;
+
+ private JComboBox phoneNumberCombo = new JComboBox();
+ private JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+ private SIPCommButton callButton;
+ private SIPCommButton hangupButton;
+
+ public CallPanel(){
+
+ super(new BorderLayout());
+
+ callButton = new SIPCommButton(callButtonBG,
+ callButtonRolloverBG,
+ callButtonIcon);
+ hangupButton = new SIPCommButton(hangupButtonBG,
+ hangupButtonRolloverBG,
+ hangupButtonIcon);
+
+ this.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
+ this.init();
+ }
+
+ private void init() {
+ this.phoneNumberCombo.setEditable(true);
+
+ this.add(phoneNumberCombo, BorderLayout.NORTH);
+
+ this.buttonsPanel.add(callButton);
+ this.buttonsPanel.add(hangupButton);
+
+ this.add(buttonsPanel, BorderLayout.CENTER);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/CommunicatorMain.java b/src/net/java/sip/communicator/impl/gui/main/CommunicatorMain.java
new file mode 100755
index 0000000..d46c2d5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/CommunicatorMain.java
@@ -0,0 +1,96 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.io.File;
+
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.UIManager;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+import javax.swing.plaf.metal.MetalTheme;
+
+import com.l2fprod.gui.plaf.skin.Skin;
+import com.l2fprod.gui.plaf.skin.SkinLookAndFeel;
+import com.l2fprod.util.OS;
+
+//import examples.demo;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * Starts the GUI application using the SkinLookAndFeel of l2fprod.
+ */
+public class CommunicatorMain {
+
+ public static void main(String[] args){
+
+ try {
+ //the theme could be passed as a parameter
+ if (args.length > 0) {
+ String themepack = args[0];
+ if (themepack.endsWith(".xml")) {
+ SkinLookAndFeel.setSkin(
+ SkinLookAndFeel.loadThemePackDefinition(new File(args[0]).toURL()));
+ UIManager.setLookAndFeel("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
+ } else if (themepack.startsWith("class:")) {
+ String classname = themepack.substring("class:".length());
+ SkinLookAndFeel.setSkin((Skin)Class.forName(classname).newInstance());
+ UIManager.setLookAndFeel("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
+ } else if (themepack.startsWith("theme:")) {
+ String classname = themepack.substring("theme:".length());
+ MetalTheme theme = (MetalTheme)Class.forName(classname).newInstance();
+ MetalLookAndFeel metal = new MetalLookAndFeel();
+ MetalLookAndFeel.setCurrentTheme(theme);
+ UIManager.setLookAndFeel(metal);
+ } else {
+ SkinLookAndFeel.setSkin(SkinLookAndFeel.loadThemePack(args[0]));
+ UIManager.setLookAndFeel("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
+ }
+ }
+ //the default theme is set if no theme is specified
+ else{
+ SkinLookAndFeel.setSkin(
+ SkinLookAndFeel.loadThemePackDefinition(new File("src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/skinlf-themepack.xml").toURL()));
+ UIManager.setLookAndFeel("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
+ }
+
+ //Decorates the frames and dialogs if we are running with jdk1.4 +
+ /*
+ if (OS.isOneDotFourOrMore()) {
+ java.lang.reflect.Method method = JFrame.class.getMethod(
+ "setDefaultLookAndFeelDecorated",
+ new Class[] { boolean.class });
+ method.invoke(null, new Object[] { Boolean.TRUE });
+
+ method = JDialog.class.getMethod(
+ "setDefaultLookAndFeelDecorated",
+ new Class[] { boolean.class });
+ method.invoke(null, new Object[] { Boolean.TRUE });
+ }*/
+
+ } catch (Exception e) { }
+
+ //Image frameIcon =
+ //new ImageIcon(demo.class.getResource("windowicon.gif")).getImage();
+ // so option pane as same icon as us
+ //JOptionPane.getRootFrame().setIconImage(frameIcon);
+
+ //TODO: To be removed when the contact list service is ready
+ ContactList clist = new ContactList();
+
+ clist.addContact(new ContactItem("user1"));
+ clist.addContact(new ContactItem("user2"));
+ clist.addContact(new ContactItem("user3"));
+
+ User user = new User();
+
+ user.setProtocols(new String[]{"ICQ", "MSN"});
+
+ MainFrame mainFrame = new MainFrame(clist, user);
+ //mainFrame.setIconImage(frameIcon);
+
+ mainFrame.setTitle("SIP Communicator");
+ mainFrame.pack();
+
+ mainFrame.setVisible(true);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/ContactItem.java b/src/net/java/sip/communicator/impl/gui/main/ContactItem.java
new file mode 100755
index 0000000..598871a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/ContactItem.java
@@ -0,0 +1,54 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.Image;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The contact.
+ * TODO: To be removed when the contact list service is ready.
+ */
+
+public class ContactItem {
+
+ private String nickname;
+ private Image photo;
+ private String[] protocolList;
+ private String status;
+
+ public ContactItem(String nickname){
+ this.nickname = nickname;
+ }
+
+ public String getNickName() {
+ return nickname;
+ }
+
+ public void setNickName(String nickname) {
+ this.nickname = nickname;
+ }
+
+ public Image getPhoto() {
+ return photo;
+ }
+
+ public void setPhoto(Image photo) {
+ this.photo = photo;
+ }
+
+ public String[] getProtocolList() {
+ return protocolList;
+ }
+
+ public void setProtocolList(String[] protocolList) {
+ this.protocolList = protocolList;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/ContactList.java b/src/net/java/sip/communicator/impl/gui/main/ContactList.java
new file mode 100644
index 0000000..70d92e3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/ContactList.java
@@ -0,0 +1,23 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.util.Vector;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The contact list.
+ * TODO: to be removed when the contact list service is ready.
+ */
+
+public class ContactList {
+
+ private Vector contacts = new Vector();
+
+ public Vector getAllContacts(){
+ return contacts;
+ }
+
+ public void addContact(ContactItem contactItem){
+ contacts.add(contactItem);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/ContactListPanel.java b/src/net/java/sip/communicator/impl/gui/main/ContactListPanel.java
new file mode 100755
index 0000000..5d3a37e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/ContactListPanel.java
@@ -0,0 +1,81 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Vector;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The ContactListPanel contains the contact list.
+ */
+public class ContactListPanel extends JScrollPane{
+
+ private ContactList clist;
+ private JPanel mainPanel = new JPanel();
+ private JPanel contactsPanel = new JPanel();
+
+ public ContactListPanel(ContactList clist){
+
+ this.mainPanel.setLayout(new BorderLayout());
+ this.contactsPanel.setLayout(new BoxLayout(this.contactsPanel, BoxLayout.Y_AXIS));
+
+ this.clist = clist;
+ this.init();
+ }
+
+ private void init(){
+
+ for (int i = 0; i < this.clist.getAllContacts().size(); i ++){
+
+ ContactPanel cpanel = new ContactPanel((ContactItem)this.clist.getAllContacts().get(i));
+ cpanel.setPreferredSize(new Dimension(LookAndFeelConstants.CONTACTPANEL_WIDTH, LookAndFeelConstants.CONTACTPANEL_HEIGHT));
+
+ cpanel.addMouseListener(new MouseAdapter(){
+ public void mouseEntered(MouseEvent e){
+ ContactPanel cpanel = (ContactPanel)e.getSource();
+
+ cpanel.setMouseOver(true);
+ cpanel.repaint();
+ }
+
+ public void mouseExited(MouseEvent e){
+ ContactPanel cpanel = (ContactPanel)e.getSource();
+
+ cpanel.setMouseOver(false);
+ cpanel.repaint();
+ }
+
+ public void mouseClicked(MouseEvent e){
+ ContactPanel cpanel = (ContactPanel)e.getSource();
+
+ cpanel.setSelected(true);
+ refreshContactsStatus(cpanel);
+ }
+ });
+
+ this.contactsPanel.add(cpanel);
+ }
+
+ this.mainPanel.add(contactsPanel, BorderLayout.NORTH);
+ this.getViewport().add(mainPanel);
+ }
+
+ public void refreshContactsStatus(ContactPanel cpanelSelected){
+
+ for (int i = 0; i < this.contactsPanel.getComponentCount(); i ++){
+ ContactPanel cpanel = (ContactPanel)this.contactsPanel.getComponent(i);
+
+ if(!cpanel.equals(cpanelSelected)){
+ cpanel.setSelected(false);
+ }
+ }
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/ContactListTree.java b/src/net/java/sip/communicator/impl/gui/main/ContactListTree.java
new file mode 100644
index 0000000..1c037e3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/ContactListTree.java
@@ -0,0 +1,7 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import javax.swing.JTree;
+
+public class ContactListTree extends JTree {
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/ContactPanel.java b/src/net/java/sip/communicator/impl/gui/main/ContactPanel.java
new file mode 100755
index 0000000..70b5b1d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/ContactPanel.java
@@ -0,0 +1,138 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Toolkit;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The ContactPanel contains the contact item.
+ */
+
+public class ContactPanel extends JPanel {
+
+ private ContactItem contactItem;
+
+ private boolean isMouseOver = false;
+ private boolean isSelected = false;
+
+ private JLabel nicknameLabel = new JLabel();
+
+ public ContactPanel(ContactItem contactItem){
+ super(new BorderLayout());
+
+ this.contactItem = contactItem;
+
+ this.init();
+ }
+
+ private void init(){
+
+ nicknameLabel.setFont(this.getFont().deriveFont(Font.BOLD));
+
+ this.setUserData();
+
+ this.add(nicknameLabel, BorderLayout.WEST);
+
+ }
+
+ public void setUserData(){
+ nicknameLabel.setText(this.contactItem.getNickName());
+ }
+
+ public void paintComponent(Graphics g){
+ super.paintComponent(g);
+
+ Graphics2D g2 = (Graphics2D)g;
+
+ if(this.isSelected()){
+ GradientPaint p = new GradientPaint(this.getWidth()/2,
+ 0,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_START_COLOR,
+ this.getWidth()/2,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_END_COLOR);
+
+ GradientPaint p1 = new GradientPaint( this.getWidth()/2,
+ this.getHeight() - LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_END_COLOR,
+ this.getWidth()/2,
+ this.getHeight(),
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_START_COLOR);
+
+ g2.setPaint(p);
+ g2.fillRect(0, 0, this.getWidth(), LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE);
+
+ g2.setColor(LookAndFeelConstants.CONTACTPANEL_SELECTED_END_COLOR);
+ g2.fillRect(0,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE,
+ this.getWidth(),
+ this.getHeight() - LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE);
+
+ g2.setPaint(p1);
+ g2.fillRect(0, this.getHeight() - LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE, this.getWidth(), this.getHeight() - 1);
+ }
+ else if(this.isMouseOver()){
+ GradientPaint p = new GradientPaint(this.getWidth()/2,
+ 0,
+ LookAndFeelConstants.CONTACTPANEL_MOVER_START_COLOR,
+ this.getWidth()/2,
+ LookAndFeelConstants.CONTACTPANEL_GRADIENT_SIZE,
+ LookAndFeelConstants.CONTACTPANEL_MOVER_END_COLOR);
+
+ GradientPaint p1 = new GradientPaint( this.getWidth()/2,
+ this.getHeight() - LookAndFeelConstants.CONTACTPANEL_GRADIENT_SIZE,
+ LookAndFeelConstants.CONTACTPANEL_MOVER_END_COLOR,
+ this.getWidth()/2,
+ this.getHeight(),
+ LookAndFeelConstants.CONTACTPANEL_MOVER_START_COLOR);
+
+ g2.setPaint(p);
+ g2.fillRect(0, 0, this.getWidth(), LookAndFeelConstants.CONTACTPANEL_GRADIENT_SIZE);
+
+ g2.setColor(LookAndFeelConstants.CONTACTPANEL_MOVER_END_COLOR);
+ g2.fillRect(0,
+ LookAndFeelConstants.CONTACTPANEL_GRADIENT_SIZE,
+ this.getWidth(),
+ this.getHeight() - LookAndFeelConstants.CONTACTPANEL_GRADIENT_SIZE);
+
+ g2.setPaint(p1);
+ g2.fillRect(0, this.getHeight() - LookAndFeelConstants.CONTACTPANEL_GRADIENT_SIZE - 1, this.getWidth(), this.getHeight() - 1);
+ }
+
+ g2.setColor(LookAndFeelConstants.CONTACTPANEL_LINES_COLOR);
+ g2.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1);
+ }
+
+ public boolean isMouseOver() {
+ return isMouseOver;
+ }
+
+ public void setMouseOver(boolean isMouseOver) {
+ this.isMouseOver = isMouseOver;
+ }
+
+ public boolean isSelected() {
+ return isSelected;
+ }
+
+ public void setSelected(boolean isSelected) {
+ if(this.isSelected != isSelected) {
+ this.isSelected = isSelected;
+ /*if(isSelected) {
+ this.setSize(new Dimension(this.getWidth(), LookAndFeelConstants.CONTACTPANEL_SELECTED_HEIGHT));
+ } else {
+ this.setSize(new Dimension(this.getWidth(), LookAndFeelConstants.CONTACTPANEL_HEIGHT));
+ }*/
+ this.repaint();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/DialPanel.java b/src/net/java/sip/communicator/impl/gui/main/DialPanel.java
new file mode 100755
index 0000000..ce45b0e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/DialPanel.java
@@ -0,0 +1,71 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The DialPanel contains the dial buttons.
+ */
+
+public class DialPanel extends JPanel {
+ private Font buttonTextFont = new Font("Verdana", Font.BOLD, 12);
+
+ private JButton oneButton = new JButton("1");
+ private JButton twoButton = new JButton("2");
+ private JButton threeButton = new JButton("3");
+ private JButton fourButton = new JButton("4");
+ private JButton fiveButton = new JButton("5");
+ private JButton sixButton = new JButton("6");
+ private JButton sevenButton = new JButton("7");
+ private JButton eightButton = new JButton("8");
+ private JButton nineButton = new JButton("9");
+ private JButton starButton = new JButton("*");
+ private JButton zeroButton = new JButton("0+");
+ private JButton diezButton = new JButton("#");
+
+ private JPanel dialPadPanel = new JPanel(new GridLayout(4, 3, 5, 5));
+
+ public DialPanel(){
+ super(new FlowLayout(FlowLayout.CENTER));
+
+ this.init();
+ }
+
+ public void init(){
+
+ oneButton.setFont(this.buttonTextFont);
+ twoButton.setFont(this.buttonTextFont);
+ threeButton.setFont(this.buttonTextFont);
+ fourButton.setFont(this.buttonTextFont);
+ fiveButton.setFont(this.buttonTextFont);
+ sixButton.setFont(this.buttonTextFont);
+ sevenButton.setFont(this.buttonTextFont);
+ eightButton.setFont(this.buttonTextFont);
+ nineButton.setFont(this.buttonTextFont);
+ zeroButton.setFont(this.buttonTextFont);
+ diezButton.setFont(this.buttonTextFont);
+ starButton.setFont(this.buttonTextFont);
+
+ dialPadPanel.add(oneButton);
+ dialPadPanel.add(twoButton);
+ dialPadPanel.add(threeButton);
+ dialPadPanel.add(fourButton);
+ dialPadPanel.add(fiveButton);
+ dialPadPanel.add(sixButton);
+ dialPadPanel.add(sevenButton);
+ dialPadPanel.add(eightButton);
+ dialPadPanel.add(nineButton);
+ dialPadPanel.add(starButton);
+ dialPadPanel.add(zeroButton);
+ dialPadPanel.add(diezButton);
+
+ this.add(dialPadPanel, BorderLayout.CENTER);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/LookAndFeelConstants.java b/src/net/java/sip/communicator/impl/gui/main/LookAndFeelConstants.java
new file mode 100755
index 0000000..97f10ea
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/LookAndFeelConstants.java
@@ -0,0 +1,284 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.Color;
+import java.awt.Image;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.imageio.ImageIO;
+import javax.swing.ImageIcon;
+
+import net.java.sip.communicator.impl.gui.main.customcontrols.StatusIcon;
+import net.java.sip.communicator.util.Logger;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * All look and feel related constants are stored here.
+ */
+
+public class LookAndFeelConstants {
+ private static Logger log = Logger.getLogger(LookAndFeelConstants.class);
+
+ /*========================================================================
+ * ------------------------ SIZE CONSTANTS --------------------------------
+ ========================================================================*/
+
+ public static final int MAINFRAME_HEIGHT = 200;
+
+ public static final int MAINFRAME_WIDTH = 30;
+
+ public static final int CONTACTPANEL_HEIGHT = 25;
+
+ public static final int CONTACTPANEL_WIDTH = 10;
+
+ public static final int CONTACTPANEL_SELECTED_HEIGHT = 50;
+
+ public static final int CONTACTPANEL_SELECTED_GRADIENT_SIZE = 10;
+
+ public static final int CONTACTPANEL_GRADIENT_SIZE = 10;
+
+
+ /*========================================================================
+ * ------------------------ COLOR CONSTANTS -------------------------------
+ ========================================================================*/
+
+ public static final Color CONTACTPANEL_SELECTED_START_COLOR =
+ new Color(166, 207, 239);
+
+ public static final Color CONTACTPANEL_SELECTED_END_COLOR =
+ new Color(255, 255, 255);
+
+ public static final Color CONTACTPANEL_MOVER_START_COLOR =
+ new Color(210, 210, 210);
+
+ // public static final Color CONTACTPANEL_MOVER_START_COLOR =
+ // new Color(244, 235, 143);
+
+ public static final Color CONTACTPANEL_MOVER_END_COLOR =
+ new Color(255, 255, 255);
+
+ public static final Color CONTACTPANEL_LINES_COLOR =
+ new Color(154, 154, 154);
+
+
+ /*=========================================================================
+ * ------------------------------ ICONS ----------------------------------
+ ========================================================================*/
+
+ public static final Image QUICK_MENU_ADD_ICON = LookAndFeelConstants
+ .loadImage("../resources/buttons/addContactIcon.png");
+
+ public static final Image QUICK_MENU_CONFIGURE_ICON = LookAndFeelConstants
+ .loadImage("../resources/buttons/configureIcon.png");
+
+ public static final Image QUICK_MENU_BUTTON_BG = LookAndFeelConstants
+ .loadImage("../resources/buttons/quickMenuButtonBg.gif");
+
+ public static final Image QUICK_MENU_BUTTON_ROLLOVER_BG = LookAndFeelConstants
+ .loadImage("../resources/buttons/quickMenuButtonRolloverBg.gif");
+
+ public static final Image CALL_BUTTON_ICON = LookAndFeelConstants
+ .loadImage("../resources/buttons/callIcon.png");
+
+ public static final Image HANG_UP_BUTTON_ICON = LookAndFeelConstants
+ .loadImage("../resources/buttons/hangupIcon.png");
+
+ public static final Image CALL_BUTTON_BG = LookAndFeelConstants
+ .loadImage("../resources/buttons/call.gif");
+
+ public static final Image HANGUP_BUTTON_BG = LookAndFeelConstants
+ .loadImage("../resources/buttons/hangUp.gif");
+
+ public static final Image CALL_ROLLOVER_BUTTON_BG = LookAndFeelConstants
+ .loadImage("../resources/buttons/callRollover.gif");
+
+ public static final Image HANGUP_ROLLOVER_BUTTON_BG = LookAndFeelConstants
+ .loadImage("../resources/buttons/hangUpRollover.gif");
+
+ public static final Image STATUS_SELECTOR_BOX = LookAndFeelConstants
+ .loadImage("../resources/buttons/combobox.png");
+
+
+ /*=========================================================================
+ * ------------------------ STATUS LABELS ---------------------------------
+ ========================================================================*/
+
+ public static final String ONLINE_STATUS = "Online";
+
+ public static final String OFFLINE_STATUS = "Offline";
+
+ public static final String OCCUPIED_STATUS = "Occupied";
+
+ public static final String CHAT_STATUS = "Free for chat";
+
+ public static final String AWAY_STATUS = "Away";
+
+ public static final String NA_STATUS = "Not available";
+
+ public static final String INVISIBLE_STATUS = "Invisible";
+
+ public static final String DND_STATUS = "Do not disturb";
+
+ /*=========================================================================
+ * ------------------------ PROTOCOL NAMES --------------------------------
+ ========================================================================*/
+
+ public static final String ICQ = "ICQ";
+
+ public static final String MSN = "MSN";
+
+ public static final String AIM = "AIM";
+
+ public static final String YAHOO = "Yahoo";
+
+ public static final String JABBER = "Jabber";
+
+ public static final String SKYPE = "Skype";
+
+ /*=========================================================================
+ * --------------------- PROTOCOLS STATUS ICONS ---------------------------
+ ========================================================================*/
+
+ public static final Image ICQ_LOGO = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/Icq16.png");
+
+ public static final Image ICQ_FF_CHAT_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_ffc.png");
+
+ public static final Image ICQ_AWAY_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_away.png");
+
+ public static final Image ICQ_NA_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_na.png");
+
+ public static final Image ICQ_DND_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_dnd.png");
+
+ public static final Image ICQ_OCCUPIED_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_occupied.png");
+
+ public static final Image ICQ_OFFLINE_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_offline.png");
+
+ public static final Image ICQ_INVISIBLE_ICON = LookAndFeelConstants
+ .loadImage("../resources/protocols/icq/cr16-action-icq_invisible.png");
+
+ public static final Image MSN_LOGO = LookAndFeelConstants
+ .loadImage("../resources/protocols/msn/Msn16.png");
+
+ public static final Image AIM_LOGO = LookAndFeelConstants
+ .loadImage("../resources/protocols/aim/Aim16.png");
+
+ public static final Image YAHOO_LOGO = LookAndFeelConstants
+ .loadImage("../resources/protocols/yahoo/Yahoo16.png");
+
+ public static final Image JABBER_LOGO = LookAndFeelConstants
+ .loadImage("../resources/protocols/jabber/Jabber16.png");
+
+ public static final Image SKYPE_LOGO = LookAndFeelConstants
+ .loadImage("../resources/protocols/skype/Skype16.png");
+
+
+ /**
+ * Gets all protocol statuses, including status and text.
+ *
+ * @param protocolName
+ * @return an ArrayList of all status Icons for the given protocol.
+ */
+
+ public static ArrayList getProtocolIcons (String protocolName) {
+ ArrayList protocolStatusList = new ArrayList ();
+
+ if (protocolName.equals (LookAndFeelConstants.ICQ)) {
+
+ protocolStatusList.add (new Status(ONLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_LOGO)));
+
+ protocolStatusList.add (new Status(CHAT_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_LOGO,
+ LookAndFeelConstants.ICQ_FF_CHAT_ICON)));
+
+ protocolStatusList.add(new Status(AWAY_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_LOGO,
+ LookAndFeelConstants.ICQ_AWAY_ICON)));
+
+ protocolStatusList.add(new Status(NA_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_LOGO,
+ LookAndFeelConstants.ICQ_NA_ICON)));
+
+ protocolStatusList.add(new Status(DND_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_LOGO,
+ LookAndFeelConstants.ICQ_DND_ICON)));
+
+ protocolStatusList.add(new Status(OCCUPIED_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_LOGO,
+ LookAndFeelConstants.ICQ_OCCUPIED_ICON)));
+
+ protocolStatusList.add(new Status(OFFLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_OFFLINE_ICON)));
+
+ protocolStatusList.add(new Status(INVISIBLE_STATUS,
+ new StatusIcon (LookAndFeelConstants.ICQ_INVISIBLE_ICON)));
+
+ } else if (protocolName.equals (LookAndFeelConstants.MSN)) {
+
+ protocolStatusList.add (new Status(ONLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.MSN_LOGO)));
+
+ } else if (protocolName.equals (LookAndFeelConstants.AIM)) {
+
+ protocolStatusList.add (new Status(ONLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.AIM_LOGO)));
+
+ } else if (protocolName.equals (LookAndFeelConstants.YAHOO)) {
+
+ protocolStatusList.add (new Status(ONLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.YAHOO_LOGO)));
+
+ } else if (protocolName.equals (LookAndFeelConstants.JABBER)) {
+
+ protocolStatusList.add (new Status(ONLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.JABBER_LOGO)));
+
+ } else if (protocolName.equals (LookAndFeelConstants.SKYPE)) {
+
+ protocolStatusList.add (new Status(ONLINE_STATUS,
+ new StatusIcon (LookAndFeelConstants.SKYPE_LOGO)));
+ }
+
+ return protocolStatusList;
+ }
+
+ /**
+ * Loads an image from a given path.
+ */
+
+ private static Image loadImage(String path) {
+ Image image = null;
+
+ try {
+ log.logEntry();
+
+ if (log.isTraceEnabled()) {
+ log.trace("Loading image : " + path + "...");
+ }
+
+ image = ImageIO.read(LookAndFeelConstants.class.getResource(path));
+
+ if (log.isTraceEnabled()) {
+ log.trace("Loading image : " + path + "... [ DONE ]");
+ }
+
+ } catch (IOException e) {
+ log.error("Failed to load image:" + path, e);
+ } finally {
+ log.logExit();
+ }
+
+ return image;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
new file mode 100755
index 0000000..2462764
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
@@ -0,0 +1,58 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The MainFrame of the application.
+ */
+public class MainFrame extends JFrame{
+
+ private JPanel mainPanel = new JPanel(new BorderLayout());
+ private JPanel menusPanel = new JPanel(new BorderLayout());
+ private Menu menu = new Menu();
+ private QuickMenu quickMenu = new QuickMenu();
+ private CallPanel callPanel = new CallPanel();
+ private StatusPanel statusPanel;
+ private MainTabbedPane tabbedPane;
+
+
+ public MainFrame(ContactList clist, User user){
+ tabbedPane = new MainTabbedPane(clist);
+ statusPanel = new StatusPanel(user.getProtocols());
+
+ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ this.setInitialBounds();
+// this.setIconImage();
+
+ this.init();
+ }
+
+ private void init(){
+ this.menusPanel.add(menu, BorderLayout.NORTH);
+ this.menusPanel.add(quickMenu, BorderLayout.CENTER);
+
+ this.mainPanel.add(tabbedPane, BorderLayout.CENTER);
+ this.mainPanel.add(callPanel, BorderLayout.SOUTH);
+
+ this.getContentPane().add(menusPanel, BorderLayout.NORTH);
+ this.getContentPane().add(mainPanel, BorderLayout.CENTER);
+ this.getContentPane().add(statusPanel, BorderLayout.SOUTH);
+ }
+
+ private void setInitialBounds(){
+ this.setLocation(Toolkit.getDefaultToolkit().getScreenSize().width - MainFrame.WIDTH, 50);
+
+ this.getContentPane().setSize( LookAndFeelConstants.MAINFRAME_WIDTH,
+ LookAndFeelConstants.MAINFRAME_HEIGHT);
+
+ this.tabbedPane.setPreferredSize(new Dimension(LookAndFeelConstants.MAINFRAME_WIDTH,
+ LookAndFeelConstants.MAINFRAME_HEIGHT));
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/MainTabbedPane.java b/src/net/java/sip/communicator/impl/gui/main/MainTabbedPane.java
new file mode 100755
index 0000000..32fbc75
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/MainTabbedPane.java
@@ -0,0 +1,30 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.ListModel;
+import javax.swing.event.ListDataListener;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The main tabbed pane containing the contact list panel, the
+ * call list panel and the dial panel.
+ */
+public class MainTabbedPane extends JTabbedPane {
+
+ private DialPanel dialPanel = new DialPanel();
+
+ public MainTabbedPane(ContactList clist){
+
+ ContactListPanel contactList = new ContactListPanel(clist);
+
+ this.addTab("Contacts", contactList);
+ this.addTab("Call list", new JPanel());
+ this.addTab("Dial", dialPanel);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/Menu.java b/src/net/java/sip/communicator/impl/gui/main/Menu.java
new file mode 100755
index 0000000..7ca520a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/Menu.java
@@ -0,0 +1,44 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The main menu.
+ */
+public class Menu extends JMenuBar {
+ private JMenu userMenu = new JMenu();
+ private JMenu toolsMenu = new JMenu();
+ private JMenu viewMenu = new JMenu();
+ private JMenu helpMenu = new JMenu();
+
+ public Menu(){
+ this.init();
+ }
+
+ private void init(){
+ userMenu.setText("User");
+ userMenu.setMnemonic('U');
+ userMenu.setToolTipText("User");
+
+ toolsMenu.setText("Tools");
+ toolsMenu.setMnemonic('T');
+ toolsMenu.setToolTipText("Tools");
+
+ viewMenu.setText("View");
+ viewMenu.setMnemonic('V');
+ viewMenu.setToolTipText("View");
+
+ helpMenu.setText("Help");
+ helpMenu.setMnemonic('H');
+ helpMenu.setToolTipText("Help");
+
+ this.add(userMenu);
+ this.add(toolsMenu);
+ this.add(viewMenu);
+ this.add(helpMenu);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/QuickMenu.java b/src/net/java/sip/communicator/impl/gui/main/QuickMenu.java
new file mode 100755
index 0000000..33c91d4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/QuickMenu.java
@@ -0,0 +1,69 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.Dimension;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JToolBar;
+
+import net.java.sip.communicator.impl.gui.main.customcontrols.SIPCommButton;
+/**
+ * @author Yana Stamcheva
+ *
+ * The quick menu.
+ */
+public class QuickMenu extends JToolBar{
+
+ private Image addButtonIcon = LookAndFeelConstants.QUICK_MENU_ADD_ICON;
+ private Image configureButtonIcon = LookAndFeelConstants.QUICK_MENU_CONFIGURE_ICON;
+
+ SIPCommButton infoButton;
+ SIPCommButton toolsButton;
+ SIPCommButton addButton;
+ SIPCommButton searchButton;
+
+ public QuickMenu(){
+
+ this.setRollover(true);
+ this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ infoButton = new SIPCommButton();
+ toolsButton = new SIPCommButton(configureButtonIcon);
+ searchButton = new SIPCommButton();
+ addButton = new SIPCommButton(addButtonIcon);
+
+ this.init();
+ }
+
+ private void init() {
+ this.add(addButton);
+ this.add(toolsButton);
+ this.add(infoButton);
+ this.add(searchButton);
+ }
+
+ public void paint(Graphics g){
+ super.paint(g);
+
+ Graphics2D g2 = (Graphics2D)g;
+
+ GradientPaint p = new GradientPaint(this.getWidth()/2,
+ 0,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_START_COLOR,
+ this.getWidth()/2,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_GRADIENT_SIZE,
+ LookAndFeelConstants.CONTACTPANEL_SELECTED_END_COLOR);
+
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ g2.setPaint(p);
+
+ //g2.dra
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/Status.java b/src/net/java/sip/communicator/impl/gui/main/Status.java
new file mode 100644
index 0000000..2928239
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/Status.java
@@ -0,0 +1,29 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.Image;
+
+import javax.swing.ImageIcon;
+
+public class Status {
+
+ private String text;
+ private Image icon;
+
+ public Status(String text, Image icon){
+ this.text = text;
+ this.icon = icon;
+ }
+
+ public Image getIcon () {
+ return icon;
+ }
+ public void setIcon (Image icon) {
+ this.icon = icon;
+ }
+ public String getText () {
+ return text;
+ }
+ public void setText (String text) {
+ this.text = text;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/StatusPanel.java b/src/net/java/sip/communicator/impl/gui/main/StatusPanel.java
new file mode 100644
index 0000000..be2f5e3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/StatusPanel.java
@@ -0,0 +1,40 @@
+package net.java.sip.communicator.impl.gui.main;
+
+import java.awt.FlowLayout;
+import java.util.ArrayList;
+
+import javax.swing.BorderFactory;
+import javax.swing.JPanel;
+
+import net.java.sip.communicator.impl.gui.main.customcontrols.SIPCommButton;
+import net.java.sip.communicator.impl.gui.main.customcontrols.StatusSelectorBox;
+
+public class StatusPanel extends JPanel {
+
+ private String[] userProtocols;
+
+ public StatusPanel(String[] userProtocols) {
+
+ this.setLayout(new FlowLayout(FlowLayout.LEFT));
+ this.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
+ LookAndFeelConstants.CONTACTPANEL_MOVER_START_COLOR));
+
+ this.userProtocols = userProtocols;
+
+ this.init();
+ }
+
+ private void init() {
+
+ for (int i = 0; i < userProtocols.length; i++) {
+
+ ArrayList protocolStatusList = LookAndFeelConstants
+ .getProtocolIcons(userProtocols[i]);
+
+ StatusSelectorBox protocolStatusCombo = new StatusSelectorBox(
+ protocolStatusList.toArray(), (Status)protocolStatusList.get(0));
+
+ this.add(protocolStatusCombo);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/gui/main/User.java b/src/net/java/sip/communicator/impl/gui/main/User.java
new file mode 100644
index 0000000..8510d6e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/User.java
@@ -0,0 +1,13 @@
+package net.java.sip.communicator.impl.gui.main;
+
+public class User {
+ private String[] userProtocols;
+
+ public void setProtocols(String[] userProtocols){
+ this.userProtocols = userProtocols;
+ }
+
+ public String[] getProtocols(){
+ return this.userProtocols;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/customcontrols/SIPCommButton.java b/src/net/java/sip/communicator/impl/gui/main/customcontrols/SIPCommButton.java
new file mode 100755
index 0000000..742c614
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/customcontrols/SIPCommButton.java
@@ -0,0 +1,125 @@
+package net.java.sip.communicator.impl.gui.main.customcontrols;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+
+import net.java.sip.communicator.impl.gui.main.LookAndFeelConstants;
+
+/**
+ * @author Yana Stamcheva
+ *
+ * The quick menu is composed of special buttons, which are specified here.
+ */
+public class SIPCommButton extends JButton {
+
+ private Image bgImage;
+
+ private Image bgRolloverImage;
+
+ private Image iconImage;
+
+ public SIPCommButton() {
+ super();
+
+ this.bgImage = LookAndFeelConstants.QUICK_MENU_BUTTON_BG;
+ this.bgRolloverImage = LookAndFeelConstants.QUICK_MENU_BUTTON_ROLLOVER_BG;
+ this.setIcon(new ImageIcon(this.bgImage));
+
+ this.setPreferredSize(new Dimension(this.bgImage.getWidth(null),
+ this.bgImage.getHeight(null)));
+ }
+
+ public SIPCommButton(String text) {
+ super(text);
+
+ this.bgImage = LookAndFeelConstants.QUICK_MENU_BUTTON_BG;
+ this.bgRolloverImage = LookAndFeelConstants.QUICK_MENU_BUTTON_ROLLOVER_BG;
+
+ this.setPreferredSize(new Dimension(this.bgImage.getWidth(null),
+ this.bgImage.getHeight(null)));
+ }
+
+ public SIPCommButton(Image iconImage) {
+ super();
+
+ this.iconImage = iconImage;
+ this.bgImage = LookAndFeelConstants.QUICK_MENU_BUTTON_BG;
+ this.bgRolloverImage = LookAndFeelConstants.QUICK_MENU_BUTTON_ROLLOVER_BG;
+
+ this.setPreferredSize(new Dimension(this.bgImage.getWidth(null),
+ this.bgImage.getHeight(null)));
+
+ this.setIcon(new ImageIcon(this.bgImage));
+ }
+
+ public SIPCommButton(Image bgImage, Image rolloverImage, Image iconImage) {
+ super();
+
+ this.iconImage = iconImage;
+ this.bgImage = bgImage;
+ this.bgRolloverImage = rolloverImage;
+
+ this.setPreferredSize(new Dimension(this.bgImage.getWidth(null),
+ this.bgImage.getHeight(null)));
+
+ this.setIcon(new ImageIcon(this.bgImage));
+ }
+
+ public void paint(Graphics g) {
+
+ g.drawImage(this.bgImage, 0, 0, this);
+
+ if (this.iconImage != null) {
+
+ g.drawImage(this.iconImage,
+ (this.bgImage.getWidth(null) -
+ this.iconImage.getWidth(null)) / 2,
+ (this.bgImage.getHeight(null) -
+ this.iconImage.getHeight(null)) / 2, this);
+ }
+
+ if (this.getModel().isRollover()) {
+
+ g.setColor(LookAndFeelConstants.CONTACTPANEL_LINES_COLOR);
+ g.drawImage(this.bgRolloverImage, 0, 0, this);
+
+ if (this.iconImage != null) {
+
+ g.drawImage(this.iconImage,
+ (this.bgImage.getWidth(null) -
+ this.iconImage.getWidth(null)) / 2,
+ (this.bgImage.getHeight(null) -
+ this.iconImage.getHeight(null)) / 2, this);
+ }
+ }
+ }
+
+ public Image getBgImage() {
+ return bgImage;
+ }
+
+ public void setBgImage(Image bgImage) {
+ this.bgImage = bgImage;
+ }
+
+ public Image getBgRolloverImage() {
+ return bgRolloverImage;
+ }
+
+ public void setBgRolloverImage(Image bgRolloverImage) {
+ this.bgRolloverImage = bgRolloverImage;
+ }
+
+ public Image getIconImage() {
+ return iconImage;
+ }
+
+ public void setIconImage(Image iconImage) {
+ this.iconImage = iconImage;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusIcon.java b/src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusIcon.java
new file mode 100644
index 0000000..4445918
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusIcon.java
@@ -0,0 +1,40 @@
+package net.java.sip.communicator.impl.gui.main.customcontrols;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+
+public class StatusIcon extends BufferedImage {
+
+ private Image bgImage;
+ private Image iconImage;
+
+
+ public StatusIcon (Image bgImage, Image iconImage) {
+ super( bgImage.getWidth(null),
+ bgImage.getHeight(null),
+ BufferedImage.TYPE_4BYTE_ABGR);
+
+ this.bgImage = bgImage;
+ this.iconImage = iconImage;
+
+ this.getGraphics().drawImage (this.bgImage, 0, 0, null);
+
+ if (this.iconImage != null)
+ this.getGraphics().drawImage (this.iconImage,
+ (this.bgImage.getWidth(null) -
+ this.iconImage.getWidth(null)) / 2,
+ (this.bgImage.getHeight(null) -
+ this.iconImage.getHeight(null)) / 2, null);
+
+ }
+
+ public StatusIcon (Image image) {
+ super( image.getWidth(null),
+ image.getHeight(null),
+ BufferedImage.TYPE_4BYTE_ABGR);
+
+ this.bgImage = image;
+
+ this.getGraphics().drawImage (this.bgImage, 0, 0, null);
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusSelectorBox.java b/src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusSelectorBox.java
new file mode 100644
index 0000000..5a45e22
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/customcontrols/StatusSelectorBox.java
@@ -0,0 +1,117 @@
+package net.java.sip.communicator.impl.gui.main.customcontrols;
+
+import java.awt.Component;
+import java.awt.Image;
+import java.awt.MenuItem;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+
+import net.java.sip.communicator.impl.gui.main.LookAndFeelConstants;
+import net.java.sip.communicator.impl.gui.main.Status;
+
+public class StatusSelectorBox extends SIPCommButton
+ implements ActionListener{
+
+ private SIPCommButton button;
+
+ private JPopupMenu popup;
+
+ private Object[] items;
+
+ private final Image statusSelectorBg = LookAndFeelConstants.STATUS_SELECTOR_BOX;
+
+ private final int width = statusSelectorBg.getWidth(null);
+
+ private final int height = statusSelectorBg.getHeight(null);
+
+ private final int iconX = (this.width - 24) / 2;
+
+ private final int iconY = (this.height - 16) / 2;
+
+ public StatusSelectorBox(Object[] items, Status currentStatus) {
+
+ super( LookAndFeelConstants.STATUS_SELECTOR_BOX,
+ LookAndFeelConstants.STATUS_SELECTOR_BOX,
+ currentStatus.getIcon());
+
+ this.popup = new JPopupMenu();
+
+ this.items = items;
+
+ this.init();
+ }
+
+ public void init() {
+
+ for (int i = 0; i < items.length; i++) {
+
+ if (items[i] instanceof Status) {
+
+ Status status = (Status) items[i];
+ JMenuItem item = new JMenuItem( status.getText(),
+ new ImageIcon(status.getIcon()));
+
+ item.addActionListener(this);
+
+ this.popup.add(item);
+ }
+ }
+
+ this.popup.setInvoker(this);
+ this.addActionListener(this);
+
+ }
+
+ public void actionPerformed (ActionEvent e) {
+
+ if (e.getSource() instanceof SIPCommButton){
+
+ if (!this.popup.isVisible()) {
+ this.popup.setLocation(this.calculatePopupLocation());
+ this.popup.setVisible(true);
+ }
+ }
+ else if (e.getSource() instanceof JMenuItem){
+
+ JMenuItem menuItem = (JMenuItem) e.getSource();
+
+ this.setIconImage(((ImageIcon)menuItem.getIcon()).getImage());
+ }
+ }
+
+ public Point calculatePopupLocation(){
+
+ Component component = this;
+ Point point = new Point();
+ int x = this.getX();
+ int y = this.getY();
+
+ while(component.getParent() != null){
+
+ component = component.getParent();
+
+ x += component.getX();
+ y += component.getY();
+ }
+
+ point.x = x;
+ point.y = y + this.getHeight();
+
+ return point;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/addContactIcon.png b/src/net/java/sip/communicator/impl/gui/resources/buttons/addContactIcon.png
new file mode 100644
index 0000000..2665b18
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/addContactIcon.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/call.gif b/src/net/java/sip/communicator/impl/gui/resources/buttons/call.gif
new file mode 100644
index 0000000..4aa7477
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/call.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/callIcon.png b/src/net/java/sip/communicator/impl/gui/resources/buttons/callIcon.png
new file mode 100644
index 0000000..6a0e972
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/callIcon.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/callRollover.gif b/src/net/java/sip/communicator/impl/gui/resources/buttons/callRollover.gif
new file mode 100644
index 0000000..7d00a0b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/callRollover.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/combobox.png b/src/net/java/sip/communicator/impl/gui/resources/buttons/combobox.png
new file mode 100644
index 0000000..c50d8a0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/combobox.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/configureIcon.png b/src/net/java/sip/communicator/impl/gui/resources/buttons/configureIcon.png
new file mode 100644
index 0000000..8706529
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/configureIcon.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/hangUp.gif b/src/net/java/sip/communicator/impl/gui/resources/buttons/hangUp.gif
new file mode 100644
index 0000000..8e743d9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/hangUp.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/hangUpRollover.gif b/src/net/java/sip/communicator/impl/gui/resources/buttons/hangUpRollover.gif
new file mode 100644
index 0000000..25e88de
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/hangUpRollover.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/hangupIcon.png b/src/net/java/sip/communicator/impl/gui/resources/buttons/hangupIcon.png
new file mode 100644
index 0000000..aa529ed
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/hangupIcon.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonBg.gif b/src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonBg.gif
new file mode 100755
index 0000000..0b59456
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonBg.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonRolloverBg.gif b/src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonRolloverBg.gif
new file mode 100644
index 0000000..11e2363
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/buttons/quickMenuButtonRolloverBg.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim.png
new file mode 100644
index 0000000..64ebb6e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim16.png
new file mode 100644
index 0000000..a06975c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/aim/Aim16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq.png
new file mode 100644
index 0000000..6a3d154
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq16.png
new file mode 100644
index 0000000..900ee44
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/Icq16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_away.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_away.png
new file mode 100644
index 0000000..81dfb45
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_away.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_dnd.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_dnd.png
new file mode 100644
index 0000000..cf94ee0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_dnd.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_ffc.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_ffc.png
new file mode 100644
index 0000000..51f5162
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_ffc.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_invisible.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_invisible.png
new file mode 100644
index 0000000..c7e37ce
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_invisible.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_na.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_na.png
new file mode 100644
index 0000000..b1aa91a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_na.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_occupied.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_occupied.png
new file mode 100644
index 0000000..d468996
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_occupied.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_offline.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_offline.png
new file mode 100644
index 0000000..a9d1103
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/icq/cr16-action-icq_offline.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber16.png
new file mode 100644
index 0000000..e8e6148
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber2.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber2.png
new file mode 100644
index 0000000..592c385
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/jabber/Jabber2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn.png
new file mode 100644
index 0000000..47b72d4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn16.png
new file mode 100644
index 0000000..6e340db
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn2-16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn2-16.png
new file mode 100644
index 0000000..9328c95
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/msn/Msn2-16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype.png
new file mode 100644
index 0000000..8c622df
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype16.png
new file mode 100644
index 0000000..19a72b5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/skype/Skype16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo.png
new file mode 100644
index 0000000..f2e7339
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo16.png b/src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo16.png
new file mode 100644
index 0000000..29d34fb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/resources/protocols/yahoo/Yahoo16.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down1.png
new file mode 100644
index 0000000..58be1f3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down2.png
new file mode 100644
index 0000000..d4c3914
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down3.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down3.png
new file mode 100644
index 0000000..d4c3914
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_down3.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left1.png
new file mode 100644
index 0000000..3bdc634
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left2.png
new file mode 100644
index 0000000..3bdc634
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left3.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left3.png
new file mode 100644
index 0000000..3bdc634
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_left3.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right1.png
new file mode 100644
index 0000000..9d536c2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right2.png
new file mode 100644
index 0000000..9d536c2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right3.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right3.png
new file mode 100644
index 0000000..9d536c2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_right3.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up1.png
new file mode 100644
index 0000000..8600612
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up2.png
new file mode 100644
index 0000000..8600612
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up3.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up3.png
new file mode 100644
index 0000000..8600612
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/arrow_up3.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/background.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/background.png
new file mode 100644
index 0000000..c64d4b2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/background.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button0.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button0.png
new file mode 100644
index 0000000..a881e6c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button0.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button1.png
new file mode 100644
index 0000000..1baa1d2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button2.png
new file mode 100644
index 0000000..f5e718f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button3.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button3.png
new file mode 100644
index 0000000..d253786
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button3.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button4.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button4.png
new file mode 100644
index 0000000..1baa1d2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button4.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button5.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button5.png
new file mode 100644
index 0000000..c3cbfd4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button5.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button6.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button6.png
new file mode 100644
index 0000000..38bbb12
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button6.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button7.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button7.png
new file mode 100644
index 0000000..1baa1d2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button7.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button8.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button8.png
new file mode 100644
index 0000000..1baa1d2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button8.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button9.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button9.png
new file mode 100644
index 0000000..d387e49
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/button9.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check1.png
new file mode 100644
index 0000000..8ee89b6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check2.png
new file mode 100644
index 0000000..3641af2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/check2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/empty.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/empty.png
new file mode 100644
index 0000000..6539ac0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/empty.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry1.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry2.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/entry2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_bottom1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_bottom1.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_bottom1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_left1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_left1.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_left1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_right1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_right1.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_right1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_top1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_top1.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/extension_top1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_end.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_end.png
new file mode 100644
index 0000000..4b6dcc2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_end.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_start.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_start.png
new file mode 100644
index 0000000..73e4763
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/frame_gap_top_start.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_end.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_end.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_end.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_start.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_start.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_bottom_start.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left.png
new file mode 100644
index 0000000..8b0ad9b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_end.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_end.png
new file mode 100644
index 0000000..d17c8c3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_end.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_start.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_start.png
new file mode 100644
index 0000000..d63a811
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_left_start.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right.png
new file mode 100644
index 0000000..31b476c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_end.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_end.png
new file mode 100644
index 0000000..5732bf1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_end.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_start.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_start.png
new file mode 100644
index 0000000..2d8ddca
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_right_start.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_end.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_end.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_end.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_start.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_start.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gap_top_start.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gtkrc b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gtkrc
new file mode 100644
index 0000000..2fe1281
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/gtkrc
@@ -0,0 +1,1224 @@
+include "testgtkrc2"
+
+module_path ".:/home/raster/themes"
+
+style "eventbox" {
+ bg_pixmap[NORMAL] = "<parent>"
+ bg_pixmap[INSENSITIVE] = "<parent>"
+ bg_pixmap[PRELIGHT] = "<parent>"
+ bg_pixmap[SELECTED] = "<parent>"
+ bg_pixmap[ACTIVE] = "<parent>"
+}
+
+class "GtkEventBox" style "eventbox"
+
+#
+# Buttons
+#
+
+style "checkradiobutton" {
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ file = "button5.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkRadioButton" style "checkradiobutton"
+class "GtkCheckButton" style "checkradiobutton"
+
+style "togglebutton"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ shadow = IN
+ file = "button2.png"
+ border = { 5,5,10,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ shadow = OUT
+ file = "button1.png"
+ border = { 10,10,10,10 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkToggleButton" style "togglebutton"
+
+style "button"
+{
+ bg[NORMAL] = "#ffffff"
+
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = NORMAL
+ shadow = OUT
+ file = "button5.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = PRELIGHT
+ shadow = OUT
+ file = "button9.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = NORMAL
+ shadow = IN
+ file = "button4.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ shadow = IN
+ file = "button3.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ shadow = OUT
+ file = "button3.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = SELECTED
+ shadow = IN
+ file = "button4.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = ACTIVE
+ shadow = IN
+ file = "button0.png"
+ border = { 10,5,5,10 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkButton" style "button"
+
+style "clist"
+{
+ bg[PRELIGHT] = "#eeeeee"
+ fg[PRELIGHT] = "#000000"
+ base[NORMAL] = "#eeeeee"
+}
+
+class "GtkCList" style "clist"
+
+style "notebook"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ state = ACTIVE
+ file = "notebook2.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = BOTTOM
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ state = ACTIVE
+ file = "notebook5.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = TOP
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ state = ACTIVE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = RIGHT
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ state = ACTIVE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = LEFT
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "notebook3.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = BOTTOM
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "notebook4.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = TOP
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "notebook7.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = RIGHT
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "notebook7.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = LEFT
+ }
+#
+# How to draw boxes with a gap on one side (ie the page of a notebook)
+#
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_file = "gap_top.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_top_start.png"
+ gap_start_border= { 2, 0, 0, 0 }
+ gap_end_file = "gap_top_end.png"
+ gap_end_border = { 0, 2, 0, 0 }
+ gap_side = TOP
+ }
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_file = "gap_bottom.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_bottom_start.png"
+ gap_start_border= { 2, 0, 0, 0 }
+ gap_end_file = "gap_bottom_end.png"
+ gap_end_border = { 0, 2, 0, 0 }
+ gap_side = BOTTOM
+ }
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_file = "gap_left.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_left_start.png"
+ gap_start_border= { 0, 0, 2, 0 }
+ gap_end_file = "gap_left_end.png"
+ gap_end_border = { 0, 0, 0, 2 }
+ gap_side = LEFT
+ }
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_file = "gap_right.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_right_start.png"
+ gap_start_border= { 0, 0, 2, 0 }
+ gap_end_file = "gap_right_end.png"
+ gap_end_border = { 0, 0, 0, 2 }
+ gap_side = RIGHT
+ }
+#
+# How to draw the box of a notebook when it isnt attached to a tab
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "notebook6.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ gap_side = TOP
+ }
+ }
+}
+
+class "GtkNotebook" style "notebook"
+
+style "menu"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "background.png"
+ border = { 3, 3, 3, 3 }
+ stretch = FALSE
+ overlay_file = "menu_shadow.png"
+ overlay_border = { 3, 3, 3, 3 }
+ overlay_stretch = TRUE
+ }
+ }
+}
+
+class "GtkMenu" style "menu"
+
+style "menuitem"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "menu_selected.png"
+ border = { 0, 0, 0, 0 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkMenuItem" style "menuitem"
+
+style "menubar"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "background.png"
+ border = { 3, 3, 3, 3 }
+ stretch = FALSE
+ }
+ }
+}
+
+class "GtkMenuBar" style "menubar"
+
+style "optionmenu"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "option_menu.png"
+ border = { 12, 32, 2, 3 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ file = "option_menu_disabled.png"
+ border = { 12, 32, 2, 3 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkOptionMenu" style "optionmenu"
+
+style "progressbar"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "bar"
+ file = "button6.png"
+ border = { 5, 5, 5, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "button5.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ }
+}
+
+class "GtkProgressBar" style "progressbar"
+class "GtkBar" style "progressbar"
+
+style "ruler"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "vruler"
+ file = "button5.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "hruler"
+ file = "button5.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkRuler" style "ruler"
+
+style "item"
+{
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ file = "button3.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ file = "button6.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkTreeItem" style "item"
+class "GtkListItem" style "item"
+
+style "window"
+{
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ file = "background.png"
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkWindow" style "window"
+
+style "curve"
+{
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "curve_bg"
+ file = "button1.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkCurve" style "curve"
+
+style "scrollbar"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = PRELIGHT
+ file = "scrollbar_horiz1.png"
+ border = { 15, 15, 2, 2 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = NORMAL
+ file = "scrollbar_horiz1.png"
+ border = { 13, 12, 2, 2 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = PRELIGHT
+ file = "scrollbar_vert1.png"
+ border = { 2, 2, 15, 15 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ file = "scrollbar_vert1.png"
+ border = { 2, 2, 15, 15 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "vtrough.png"
+ border = { 3, 3, 23, 23 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "htrough.png"
+ border = { 23, 23, 3, 3 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ }
+}
+
+class "GtkScrollbar" style "scrollbar"
+
+style "pane"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ orientation = HORIZONTAL
+ file = "empty.png"
+ }
+ image
+ {
+ function = BOX
+ orientation = VERTICAL
+ file = "empty.png"
+ }
+ image
+ {
+ function = HANDLE
+ orientation = HORIZONTAL
+ file = "splitpane_hhandle.png"
+ }
+ image
+ {
+ function = HANDLE
+ orientation = VERTICAL
+ file = "splitpane_vhandle.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = LEFT
+ file = "splitpane_leftarrow.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = RIGHT
+ file = "splitpane_rightarrow.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = DOWN
+ file = "splitpane_downarrow.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = UP
+ file = "splitpane_uparrow.png"
+ }
+
+ }
+}
+
+class "GtkPaned" style "pane"
+
+style "range"
+{
+ engine "pixmap" {
+ image
+ {
+ function = SLIDER
+ recolorable = TRUE
+ file = "slider_hth2.png"
+ border = { 2, 2, 5, 5 }
+ stretch = FALSE
+ overlay_file = "slider_horiz1.png"
+ overlay_border = { 5, 5, 5, 5 }
+ overlay_stretch = FALSE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = SLIDER
+ recolorable = TRUE
+ file = "slider_vth2.png"
+ border = { 5, 5, 2, 2 }
+ stretch = FALSE
+ overlay_file = "slider_vert1.png"
+ overlay_border = { 5, 5, 5, 5 }
+ overlay_stretch = FALSE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "slider_vth1.png"
+ border = { 5, 2, 2, 2 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "slider_hth1.png"
+ border = { 2, 2, 5, 2 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ }
+}
+class "GtkRange" style "range"
+
+style "default"
+{
+ font = "-*-helvetica-medium-r-normal--10-*-*-*-*-*-*-*"
+ fg[NORMAL] = { 0.00, 0.00, 0.00 }
+ fg[PRELIGHT] = { 0.00, 0.00, 0.00 }
+ fg[ACTIVE] = { 0.00, 0.00, 0.00 }
+ fg[SELECTED] = { 0.00, 0.00, 0.00 }
+ fg[INSENSITIVE] = { 0.70, 0.70, 0.70 }
+ bg[NORMAL] = "#ffffff"
+ bg[PRELIGHT] = "#ffffff"
+ bg[ACTIVE] = "#ffffff"
+ bg[INSENSITIVE] = "#ffffff"
+ bg[SELECTED] = "#6ba5e7"
+ base[NORMAL] = "#ffffff"
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = PRELIGHT
+ file = "scrollbar_horiz1.png"
+ border = { 15, 15, 2, 2 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = NORMAL
+ file = "scrollbar_horiz1.png"
+ border = { 13, 12, 2, 2 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = PRELIGHT
+ file = "scrollbar_vert1.png"
+ border = { 2, 2, 15, 15 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ file = "scrollbar_vert1.png"
+ border = { 2, 2, 15, 15 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+#
+# Any trough....
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "vtrough.png"
+ border = { 3, 3, 23, 23 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+# file = "button5.png"
+# border = { 10, 10, 10, 10 }
+ file = "htrough.png"
+ border = { 23, 23, 3, 3 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "bar"
+ file = "scrollbar_horiz2.png"
+ border = { 36, 36, 2, 2 }
+ stretch = TRUE
+ }
+#
+# Handlebox
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "handlebox_bin"
+ file = "button1.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ }
+#
+# Paned widget
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "paned"
+ file = "button5.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ }
+#
+# Tooltips
+#
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "tooltip"
+ file = "button5.png"
+ border = { 5, 5, 5, 5 }
+ stretch = TRUE
+ }
+#
+# Selected text in entries, text widget, lists and trees
+#
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ detail = "selected"
+ file = "button5.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "selected"
+ file = "button2.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ detail = "text"
+ file = "textborder.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "text"
+ file = "textborder.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "viewportbin"
+ file = "background.png"
+ stretch = FALSE
+ }
+#
+# Arrows for all occasions
+#
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_up1.png"
+ stretch = FALSE
+ arrow_direction = UP
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_up2.png"
+ stretch = FALSE
+ arrow_direction = UP
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_up3.png"
+ stretch = FALSE
+ arrow_direction = UP
+ }
+
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_down1.png"
+ stretch = FALSE
+ arrow_direction = DOWN
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_down2.png"
+ stretch = FALSE
+ arrow_direction = DOWN
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_down3.png"
+ stretch = FALSE
+ arrow_direction = DOWN
+ }
+
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_left1.png"
+ stretch = FALSE
+ arrow_direction = LEFT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_left2.png"
+ stretch = FALSE
+ arrow_direction = LEFT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_left3.png"
+ stretch = FALSE
+ arrow_direction = LEFT
+ }
+
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_right1.png"
+ stretch = FALSE
+ arrow_direction = RIGHT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_right2.png"
+ stretch = FALSE
+ arrow_direction = RIGHT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_right3.png"
+ stretch = FALSE
+ arrow_direction = RIGHT
+ }
+#
+# Hline and Vline widgets
+#
+ image
+ {
+ function = HLINE
+ recolorable = TRUE
+ file = "hline.png"
+ border = { 0, 0, 1, 1 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = VLINE
+ recolorable = TRUE
+ file = "vline.png"
+ border = { 1, 1, 0, 0 }
+ stretch = TRUE
+ }
+#
+# Check marks
+#
+ image
+ {
+ function = CHECK
+ recolorable = TRUE
+ shadow = OUT
+ overlay_file = "check1.png"
+ overlay_stretch = FALSE
+ }
+ image
+ {
+ function = CHECK
+ recolorable = TRUE
+ shadow = IN
+ overlay_file = "check2.png"
+ overlay_stretch = FALSE
+ }
+#
+# Option marks
+#
+ image
+ {
+ function = OPTION
+ recolorable = TRUE
+ shadow = OUT
+ overlay_file = "option1.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ }
+ image
+ {
+ function = OPTION
+ recolorable = TRUE
+ shadow = IN
+ overlay_file = "option2.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ }
+#
+# The "tab" on the OptionMenu
+#
+# image
+# {
+# function = TAB
+# recolorable = TRUE
+# overlay_file = "button2.png"
+# overlay_stretch = FALSE
+# }
+#
+# Fun with Scrollbars
+#
+ image
+ {
+ function = SLIDER
+ recolorable = TRUE
+ file = "scrollbar_horiz1.png"
+ border = { 13, 12, 2, 2 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = SLIDER
+ recolorable = TRUE
+ file = "scrollbar_vert1.png"
+ border = { 2, 2, 13, 12 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+#
+# The handle on Handleboxes
+#
+ image
+ {
+ function = HANDLE
+ recolorable = TRUE
+ file = "button5.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ overlay_file = "handle_vert_thumb.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ orientation = VERTICAL
+ }
+
+ image
+ {
+ function = HANDLE
+ recolorable = TRUE
+ file = "button5.png"
+ border = { 10, 5, 5, 10 }
+ stretch = TRUE
+ overlay_file = "handle_horiz_thumb.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ orientation = HORIZONTAL
+ }
+
+#
+# The background for entry widgets
+#
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ detail = "entry_bg"
+ file = "entry2.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "entry_bg"
+ file = "entry1.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ }
+#
+# How to draw the focus around a widget
+#
+ image
+ {
+ function = FOCUS
+ recolorable = TRUE
+ overlay_file = "focus.png"
+ overlay_border = { 4, 4, 4, 4 }
+ overlay_stretch = TRUE
+ }
+#
+# How to draw shadows in general
+#
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = IN
+ file = "shadow2.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = OUT
+ file = "shadow1.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = ETCHED_IN
+ file = "frame1.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = ETCHED_OUT
+ file = "frame2.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+#
+# How to draw shadows with a gap on one side
+#
+ image
+ {
+ function = SHADOW_GAP
+ recolorable = TRUE
+ file = "frame_gap.png"
+ border = { 2, 2, 2, 2 }
+ stretch = FALSE
+ gap_start_file = "frame_gap_top_start.png"
+ gap_start_border= { 0, 0, 1, 1 }
+ gap_end_file = "frame_gap_top_end.png"
+ gap_end_border = { 0, 2, 1, 1 }
+ gap_side = TOP
+ }
+#
+# Some defaults as to how to draw boxes if they haven't already been covered
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "hruler"
+ file = "button5.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "vruler"
+ file = "button5.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ shadow = IN
+ file = "button2.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "button7.png"
+ border = { 10, 10, 10, 10 }
+ stretch = TRUE
+ }
+ }
+}
+
+
+# common default
+class "GtkWidget" style "default"
+
+
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_horiz_thumb.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_horiz_thumb.png
new file mode 100644
index 0000000..410a2f8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_horiz_thumb.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_vert_thumb.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_vert_thumb.png
new file mode 100644
index 0000000..65d2f1d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/handle_vert_thumb.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/hline.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/hline.png
new file mode 100644
index 0000000..f523ac9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/hline.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/htrough.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/htrough.png
new file mode 100644
index 0000000..b943509
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/htrough.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/mainbackground.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/mainbackground.png
new file mode 100644
index 0000000..970413f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/mainbackground.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_selected.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_selected.png
new file mode 100644
index 0000000..1e51f96
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_selected.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_shadow.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_shadow.png
new file mode 100644
index 0000000..2b81419
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menu_shadow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menubar.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menubar.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/menubar.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook1.png
new file mode 100644
index 0000000..f91777b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook2.png
new file mode 100644
index 0000000..c6c891a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook3.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook3.png
new file mode 100644
index 0000000..8ab49e2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook3.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook4.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook4.png
new file mode 100644
index 0000000..09010a6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook4.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook5.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook5.png
new file mode 100644
index 0000000..53c5661
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook5.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook6.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook6.png
new file mode 100644
index 0000000..5db655f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook6.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook7.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook7.png
new file mode 100644
index 0000000..38bbb12
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/notebook7.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option1.png
new file mode 100644
index 0000000..9b02817
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option2.png
new file mode 100644
index 0000000..e9d5c28
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu.png
new file mode 100644
index 0000000..009a23d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu_disabled.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu_disabled.png
new file mode 100644
index 0000000..fa98440
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/option_menu_disabled.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz1.png
new file mode 100644
index 0000000..b8ae13c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz2.png
new file mode 100644
index 0000000..3a5703e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_horiz2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_vert1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_vert1.png
new file mode 100644
index 0000000..07bb5d6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/scrollbar_vert1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow1.png
new file mode 100644
index 0000000..5c96bc4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow2.png
new file mode 100644
index 0000000..6d77304
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/shadow2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_horiz1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_horiz1.png
new file mode 100644
index 0000000..79fa938
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_horiz1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth1.png
new file mode 100644
index 0000000..ec40814
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth2.png
new file mode 100644
index 0000000..099ef64
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_hth2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vert1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vert1.png
new file mode 100644
index 0000000..9ef7671
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vert1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth1.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth1.png
new file mode 100644
index 0000000..e6d2f36
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth1.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth2.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth2.png
new file mode 100644
index 0000000..1e41fa6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/slider_vth2.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_downarrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_downarrow.png
new file mode 100644
index 0000000..ac40dd9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_downarrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_hhandle.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_hhandle.png
new file mode 100644
index 0000000..d503cc7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_hhandle.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_leftarrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_leftarrow.png
new file mode 100644
index 0000000..4bf8a1a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_leftarrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_rightarrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_rightarrow.png
new file mode 100644
index 0000000..9cd4b35
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_rightarrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_uparrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_uparrow.png
new file mode 100644
index 0000000..2dc2354
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_uparrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_vhandle.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_vhandle.png
new file mode 100644
index 0000000..85b6ab1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/splitpane_vhandle.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/textborder.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/textborder.png
new file mode 100644
index 0000000..12e4e4d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/textborder.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vline.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vline.png
new file mode 100644
index 0000000..10bbc9f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vline.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vtrough.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vtrough.png
new file mode 100644
index 0000000..1459804
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/gtk/vtrough.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Computer16.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Computer16.gif
new file mode 100644
index 0000000..824faff
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Computer16.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Default.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Default.gif
new file mode 100644
index 0000000..9f215e6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Default.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Error.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Error.gif
new file mode 100644
index 0000000..0dbcc43
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Error.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewDetails18.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewDetails18.gif
new file mode 100644
index 0000000..0e255e9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewDetails18.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewList18.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewList18.gif
new file mode 100644
index 0000000..4ea5b5e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FileViewList18.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Floppy16.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Floppy16.gif
new file mode 100644
index 0000000..c9ab12f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Floppy16.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Folder16.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Folder16.gif
new file mode 100644
index 0000000..8d47dfe
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Folder16.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderNew18.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderNew18.gif
new file mode 100644
index 0000000..902e442
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderNew18.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderUp18.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderUp18.gif
new file mode 100644
index 0000000..ddb5bcd
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FolderUp18.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FrameDefault.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FrameDefault.gif
new file mode 100644
index 0000000..2a19c3f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/FrameDefault.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Harddisk16.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Harddisk16.gif
new file mode 100644
index 0000000..49f9a81
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Harddisk16.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Home18.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Home18.gif
new file mode 100644
index 0000000..a84fda1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Home18.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Inform.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Inform.gif
new file mode 100644
index 0000000..1a18a13
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Inform.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Information.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Information.gif
new file mode 100644
index 0000000..ddfb94d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Information.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Page16.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Page16.gif
new file mode 100644
index 0000000..fc53866
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Page16.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Question.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Question.gif
new file mode 100644
index 0000000..3eff0e8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Question.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/TreeClosed.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/TreeClosed.gif
new file mode 100644
index 0000000..fa4cf82
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/TreeClosed.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Warn.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Warn.gif
new file mode 100644
index 0000000..2a09a87
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/icons/Warn.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/CosmicGelDj4.gif b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/CosmicGelDj4.gif
new file mode 100644
index 0000000..2f0bbe1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/CosmicGelDj4.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/activetitle.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/activetitle.PNG
new file mode 100644
index 0000000..070d439
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/activetitle.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/aquabackground.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/aquabackground.PNG
new file mode 100644
index 0000000..1cdcec7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/aquabackground.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/bondiblue.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/bondiblue.PNG
new file mode 100644
index 0000000..cb5caaf
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/bondiblue.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close.PNG
new file mode 100644
index 0000000..8de4516
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_disabled.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_disabled.PNG
new file mode 100644
index 0000000..0f0ebb7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_disabled.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_down.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_down.PNG
new file mode 100644
index 0000000..ee54a90
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/close_down.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify.PNG
new file mode 100644
index 0000000..80a5e49
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_disabled.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_disabled.PNG
new file mode 100644
index 0000000..422cfa2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_disabled.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_down.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_down.PNG
new file mode 100644
index 0000000..9249d26
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/iconify_down.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/inactivetitle.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/inactivetitle.PNG
new file mode 100644
index 0000000..bb21f15
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/inactivetitle.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kde.themerc b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kde.themerc
new file mode 100644
index 0000000..f66994f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kde.themerc
@@ -0,0 +1,132 @@
+[General]
+name=kAqua
+author=Jeff Marlow
+email=jeff@bluegenesis.com
+homepage=http://jeff.marlow.net
+description=Apple's Aqua (Mac OS X)\nThanks to Dangeruss for the Graphics\nThanks to Steve Jobs for the Vision
+version=1.03
+
+[Panel]
+background=panelx.PNG
+
+[File Manager]
+# Kfm's common background image:
+# backgroundImage=kfmbackground.PNG
+# Kfm's colors:
+htmlBackground=255,255,255
+htmlForeground=0,0,0
+htmlLinks=35,107,200
+htmlFollowedLinks=25,73,144
+
+[Konsole]
+schema=MacOSX.schema
+background=bondiblue.PNG
+
+[Display]
+CommonDesktop=True
+Wallpaper0=aquabackground.PNG
+WallpaperMode0=Scaled
+Wallpaper1=aquabackground.PNG
+WallpaperMode1=Scaled
+Wallpaper2=aquabackground.PNG
+WallpaperMode2=Scaled
+Wallpaper3=aquabackground.PNG
+WallpaperMode3=Scaled
+Wallpaper4=aquabackground.PNG
+WallpaperMode4=Scaled
+Wallpaper5=aquabackground.PNG
+WallpaperMode5=Scaled
+Wallpaper6=aquabackground.PNG
+WallpaperMode6=Scaled
+Wallpaper7=aquabackground.PNG
+WallpaperMode7=Scaled
+RootIconTextStyle=1
+RootIconTextForeground=0,0,27
+RootIconTextBackground=240,247,255
+
+[Colors]
+foreground=0,0,0
+selectForeground=255,255,255
+activeBlend=53,99,144
+selectBackground=25,73,144
+inactiveBackground=128,128,128
+contrast=7
+background=233,237,247
+activeBackground=233,233,233
+inactiveBlend=192,192,192
+inactiveForeground=103,105,145
+activeForeground=0,0,0
+windowForeground=0,0,0
+windowBackground=255,255,255
+terminalForeground=black
+terminalBackground=ghostwhite
+
+
+[Window Titlebar]
+#CloseButton=close.PNG
+#CloseDownButton=close_down.PNG
+#CloseInactiveButton=close_disabled.PNG
+
+CloseButton=CosmicGelDj4.gif
+CloseDownButton=CosmicGelDj4.gif
+CloseInactiveButton=CosmicGelDj4.gif
+
+MaximizeButton=maximize.PNG
+MaximizeDownButton=maximizedown.PNG
+MaximizeInactiveButton=maximize_disabled.PNG
+
+MenuButton=menu.PNG
+
+MinimizeButton=iconify.PNG
+MinimizeDownButton=iconify_down.PNG
+MinimizeInactiveButton=iconify_disabled.PNG
+
+StickyButton=sticky.PNG
+StickyDownButton=stickydown.PNG
+
+TitlebarPixmapActive=titlebar_selected.png
+TitlebarPixmapActiveBorder=80, 80, 0, 16
+TitlebarPixmapActiveLeft=
+TitlebarPixmapActiveRight=
+TitlebarPixmapActiveTop=
+TitlebarPixmapActiveBottom=
+TitlebarPixmapInactive=titlebar_unselected.png
+
+PixmapUnderTitleText=yes
+TitleFrameShaded=no
+TitleAlignment=middle
+TitleAbsolutePosition=yes
+
+[Window Border]
+shapePixmapTop=
+shapePixmapBottom=window_bottom.png
+shapePixmapLeft=window_left.png
+shapePixmapRight=window_right.png
+shapePixmapTopLeft=window_topleft.png
+shapePixmapTopRight=window_topright.png
+shapePixmapBottomLeft=window_bottomleft.png
+shapePixmapBottomRight=window_bottomright.png
+
+[Window Button Layout]
+ButtonA=Off
+ButtonB=Maximize
+ButtonC=Iconify
+ButtonD=Off
+ButtonE=Off
+ButtonF=Close
+
+[Window Gimmick]
+
+[Sounds]
+WindowShadeDown=RollUp.wav
+WindowShadeUp=RollUp.wav
+WindowClose=Close.wav
+
+[Icons]
+PanelGo=go.PNG:mini-go.PNG
+inode/directory=folder_blue.PNG:mini_folder_blue.PNG
+
+[Extra Icons]
+Extra1=netscape.PNG:mini-netscape.PNG
+Extra2=icq.PNG:mini-icq.PNG
+
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kfmbackground.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kfmbackground.PNG
new file mode 100644
index 0000000..2d6924b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/kfmbackground.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize.PNG
new file mode 100644
index 0000000..b28e5de
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize_disabled.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize_disabled.PNG
new file mode 100644
index 0000000..ecea2a4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximize_disabled.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximizedown.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximizedown.PNG
new file mode 100644
index 0000000..cb365c8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/maximizedown.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/menu.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/menu.PNG
new file mode 100644
index 0000000..477b37e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/menu.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/panelx.PNG b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/panelx.PNG
new file mode 100644
index 0000000..660cf50
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/panelx.PNG
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_selected.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_selected.png
new file mode 100644
index 0000000..2b61dd3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_selected.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_unselected.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_unselected.png
new file mode 100644
index 0000000..cb8ac09
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/titlebar_unselected.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottom.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottom.png
new file mode 100644
index 0000000..24ef2ed
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottom.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomleft.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomleft.png
new file mode 100644
index 0000000..ade162b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomleft.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomright.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomright.png
new file mode 100644
index 0000000..1450e8e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_bottomright.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_left.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_left.png
new file mode 100644
index 0000000..95c4d09
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_left.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_right.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_right.png
new file mode 100644
index 0000000..3092cdf
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_right.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topleft.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topleft.png
new file mode 100644
index 0000000..2919eb2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topleft.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topright.png b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topright.png
new file mode 100644
index 0000000..c26cb32
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/kde/window_topright.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/skinlf-themepack.xml b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/skinlf-themepack.xml
new file mode 100644
index 0000000..de368cc
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/aquathemepack/skinlf-themepack.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<skinlf-themepack require="1.2.4">
+
+ <property name="EnableBorders" value="true" />
+ <property name="JDesktopPane.backgroundEnabled" value="false" />
+ <property name="ScrollBar.alternateLayout" value="true" />
+ <property name="PopupMenu.animation" value="false"/>
+ <property name="JSplitPane.alternateUI" value="true" />
+
+ <font name="Global" value="SansSerif,0,11"/>
+
+ <skin>
+ <skin url="gtk/gtkrc"></skin>
+ <skin url="kde/kde.themerc"></skin>
+ </skin>
+
+</skinlf-themepack>
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_down.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_down.png
new file mode 100644
index 0000000..40e9214
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_down.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_down.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_down.png
new file mode 100644
index 0000000..f5da126
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_down.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_left.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_left.png
new file mode 100644
index 0000000..03f5b3f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_left.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_right.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_right.png
new file mode 100644
index 0000000..68cdc12
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_right.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_up.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_up.png
new file mode 100644
index 0000000..754797d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_in_up.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_left.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_left.png
new file mode 100644
index 0000000..848aee1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_left.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_right.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_right.png
new file mode 100644
index 0000000..50e8408
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_right.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_down.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_down.png
new file mode 100644
index 0000000..3c27fef
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_down.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_left.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_left.png
new file mode 100644
index 0000000..ae69546
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_left.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_right.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_right.png
new file mode 100644
index 0000000..163305d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_right.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_up.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_up.png
new file mode 100644
index 0000000..c05a591
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_rollover_up.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_up.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_up.png
new file mode 100644
index 0000000..c05a591
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/arrow_up.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_active.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_active.png
new file mode 100644
index 0000000..6ba9e8e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_active.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_in.png
new file mode 100644
index 0000000..7ebf4a0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_out.png
new file mode 100644
index 0000000..3e6f324
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_disabled_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_in.png
new file mode 100644
index 0000000..2eade1c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_normal_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_normal_in.png
new file mode 100644
index 0000000..85dee5e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_normal_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_out.png
new file mode 100644
index 0000000..cb51951
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_rollover_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_rollover_out.png
new file mode 100644
index 0000000..de00b5f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_rollover_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_selected.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_selected.png
new file mode 100644
index 0000000..7c83858
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/button_selected.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_in.png
new file mode 100644
index 0000000..4a8fd3a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_out.png
new file mode 100644
index 0000000..e176316
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/check_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/empty.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/empty.png
new file mode 100644
index 0000000..6539ac0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/empty.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/gtkrc b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/gtkrc
new file mode 100644
index 0000000..5caf710
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/gtkrc
@@ -0,0 +1,1079 @@
+
+style "eventbox" {
+ bg_pixmap[NORMAL] = "<parent>"
+ bg_pixmap[INSENSITIVE] = "<parent>"
+ bg_pixmap[PRELIGHT] = "<parent>"
+ bg_pixmap[SELECTED] = "<parent>"
+ bg_pixmap[ACTIVE] = "<parent>"
+}
+
+class "GtkEventBox" style "eventbox"
+
+style "pane"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ orientation = HORIZONTAL
+ file = "empty.png"
+ }
+ image
+ {
+ function = BOX
+ orientation = VERTICAL
+ file = "empty.png"
+ }
+ image
+ {
+ function = HANDLE
+ orientation = HORIZONTAL
+ file = "splitpane_hhandle.png"
+ }
+ image
+ {
+ function = HANDLE
+ orientation = VERTICAL
+ file = "splitpane_vhandle.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = LEFT
+ file = "splitpane_leftarrow.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = RIGHT
+ file = "splitpane_rightarrow.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = DOWN
+ file = "splitpane_downarrow.png"
+ }
+ image
+ {
+ function = ARROW
+ arrow_direction = UP
+ file = "splitpane_uparrow.png"
+ }
+
+ }
+}
+
+class "GtkPaned" style "pane"
+
+style "checkradiobutton" {
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ file = "highlight.png"
+ border = { 0, 0, 0, 1 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkScrollbar" style "scrollbar"
+
+style "scrollbar" {
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "scrollbar_htrough.png"
+ border = { 9, 2, 1, 1 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "scrollbar_vtrough.png"
+ border = { 1, 1, 9, 2 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+ }
+}
+
+class "GtkRadioButton" style "checkradiobutton"
+class "GtkCheckButton" style "checkradiobutton"
+
+style "togglebutton"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ shadow = IN
+ file = "toggle_in.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = PRELIGHT
+ shadow = OUT
+ file = "toggle_rollover_out.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ shadow = IN
+ file = "toggle_disabled_in.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ shadow = OUT
+ file = "toggle_disabled_out.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ shadow = OUT
+ file = "toggle_out.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkToggleButton" style "togglebutton"
+
+style "button"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = NORMAL
+ detail = "buttondefault"
+ shadow = IN
+ file = "button_in.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = NORMAL
+ shadow = OUT
+ file = "button_out.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = PRELIGHT
+ shadow = OUT
+ file = "button_rollover_out.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = NORMAL
+ shadow = IN
+ file = "button_normal_in.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ shadow = IN
+ file = "button_disabled_in.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ shadow = OUT
+ file = "button_disabled_out.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = SELECTED
+ shadow = IN
+ file = "button_selected.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = ACTIVE
+ shadow = IN
+ file = "button_active.png"
+ border = { 7, 7, 4, 5 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkButton" style "button"
+
+style "clist"
+{
+ bg[PRELIGHT] = "#ffffff"
+ fg[PRELIGHT] = "#000000"
+ base[NORMAL] = "#ffffff"
+}
+
+class "GtkCList" style "clist"
+
+style "notebook"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ state = ACTIVE
+ file = "tab_active.png"
+ border = { 11, 11, 5, 6 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "tab_active_bottom.png"
+ border = { 11, 11, 5, 6 }
+ stretch = TRUE
+ gap_side = BOTTOM
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "tab_bottom.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ gap_side = TOP
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "tab_left.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ gap_side = RIGHT
+ }
+ image
+ {
+ function = EXTENSION
+ recolorable = TRUE
+ file = "tab_right.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ gap_side = LEFT
+ }
+#
+# How to draw boxes with a gap on one side (ie the page of a notebook)
+#
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "tab_border.png"
+ border = { 17, 18, 10, 7 }
+ stretch = TRUE
+ gap_file = "gap_top.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_top_start.png"
+ gap_start_border= { 2, 0, 0, 0 }
+ gap_end_file = "gap_top_end.png"
+ gap_end_border = { 0, 2, 0, 0 }
+ gap_side = TOP
+ }
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ gap_file = "gap_bottom.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_bottom_start.png"
+ gap_start_border= { 2, 0, 0, 0 }
+ gap_end_file = "gap_bottom_end.png"
+ gap_end_border = { 0, 2, 0, 0 }
+ gap_side = BOTTOM
+ }
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ gap_file = "gap_left.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_left_start.png"
+ gap_start_border= { 0, 0, 2, 0 }
+ gap_end_file = "gap_left_end.png"
+ gap_end_border = { 0, 0, 0, 2 }
+ gap_side = LEFT
+ }
+ image
+ {
+ function = BOX_GAP
+ recolorable = TRUE
+ file = "notebook.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ gap_file = "gap_right.png"
+ gap_border = { 0, 0, 0, 0 }
+ gap_start_file = "gap_right_start.png"
+ gap_start_border= { 0, 0, 2, 0 }
+ gap_end_file = "gap_right_end.png"
+ gap_end_border = { 0, 0, 0, 2 }
+ gap_side = RIGHT
+ }
+#
+# How to draw the box of a notebook when it isnt attached to a tab
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "notebook.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ gap_side = TOP
+ }
+ }
+}
+
+class "GtkNotebook" style "notebook"
+
+style "menu"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "menu_border.png"
+ border = { 82, 91, 9, 10 }
+ stretch = TRUE
+# overlay_file = "UIS{Image:Personality/MenuBorders#0,1|menu_border_overlay.png}"
+# overlay_border = { 1, 1, 1, 1 }
+ overlay_stretch = TRUE
+ }
+ }
+}
+
+class "GtkMenu" style "menu"
+
+style "menuitem"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+# file = "menuitem.png"
+ file = "menuitem.png"
+ border = { 14, 13, 4, 4 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkMenuItem" style "menuitem"
+
+style "optionmenu"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "optionmenu_rollover.png"
+ border = { 4, 24, 2, 4 }
+ stretch = TRUE
+ arrow = "false"
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ file = "optionmenu_disabled.png"
+ border = { 4, 24, 2, 4 }
+ stretch = TRUE
+ arrow = "false"
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "optionmenu.png"
+ border = { 4, 24, 2, 4 }
+ stretch = TRUE
+ arrow = "false"
+ }
+ }
+}
+
+class "GtkOptionMenu" style "optionmenu"
+
+style "progressbar"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "bar"
+ file = "progress.png"
+ border = { 2, 2, 3, 4 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ detail = "trough"
+ file = "progress_track.png"
+ border = { 1, 1, 1, 2 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkProgressBar" style "progressbar"
+
+style "ruler"
+{
+ engine "pixmap" {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "vruler"
+ file = "button_inactive.png"
+ border = { 5, 5, 5, 5 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "hruler"
+ file = "button_inactive.png"
+ border = { 5, 5, 5, 5 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkRuler" style "ruler"
+
+style "item"
+{
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ file = "slider_disabled.png"
+ border = { 4, 4, 3, 1 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ file = "slider.png"
+ border = { 4, 4, 3, 1 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkTreeItem" style "item"
+class "GtkListItem" style "item"
+
+style "window"
+{
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ #file = "greybg.png"
+ border = { 5, 5, 5, 5 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkWindow" style "window"
+
+style "curve"
+{
+ engine "pixmap" {
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "curve_bg"
+ file = "greybg.png"
+ border = { 0, 0, 0, 0 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkCurve" style "curve"
+
+style "default"
+{
+ engine "pixmap"
+ {
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = PRELIGHT
+ file = "sliderthumb_rollover_horizontal.png"
+ border = { 13, 13, 0, 0 }
+ stretch = TRUE
+ overlay_file = "sliderthumb_rollover_horizontal.png"
+ overlay_border = { 13, 13, 0, 0 }
+ overlay_stretch = FALSE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = NORMAL
+ file = "sliderthumb_horizontal.png"
+ border = { 13, 13, 0, 0 }
+ stretch = TRUE
+ file = "sliderthumb_horizontal.png"
+ overlay_border = { 13, 13, 0, 0 }
+ overlay_stretch = FALSE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = PRELIGHT
+ file = "sliderthumb_rollover_vertical.png"
+ border = { 0, 0, 13, 13 }
+ stretch = TRUE
+ overlay_file = "sliderthumb_rollover_vertical.png"
+ overlay_border = { 0, 0, 13, 13 }
+ overlay_stretch = FALSE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "slider"
+ state = NORMAL
+ file = "sliderthumb_vertical.png"
+ border = { 0, 0, 13, 13 }
+ stretch = TRUE
+ overlay_file = "sliderthumb_vertical.png"
+ overlay_border = { 0, 0, 13, 13 }
+ overlay_stretch = FALSE
+ orientation = VERTICAL
+ }
+#
+# Any trough....
+#
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ detail = "trough"
+ file = "trough.png"
+ border = { 4, 4, 3, 1 }
+ stretch = TRUE
+ }
+#
+# Selected text in entries, text widget, lists and trees
+#
+# image
+# {
+# function = FLAT_BOX
+# recolorable = TRUE
+# state = INSENSITIVE
+# detail = "selected"
+# file = "UIS{Image:SunkEdge/Image#1,4}"
+# border = { 4, 4, 3, 1 }
+# stretch = TRUE
+# }
+# image
+# {
+# function = FLAT_BOX
+# recolorable = TRUE
+# detail = "selected"
+# file = "UIS{Image:SunkEdge/Image#1,4}"
+# border = { 4, 4, 3, 1 }
+# stretch = TRUE
+# }
+# image
+# {
+# function = FLAT_BOX
+# recolorable = TRUE
+# state = INSENSITIVE
+# detail = "text"
+# file = "UIS{Image:SunkEdge/Image#1,4}"
+# border = { 4, 4, 3, 1 }
+# stretch = TRUE
+# }
+# image
+# {
+# function = FLAT_BOX
+# recolorable = TRUE
+# detail = "text"
+# file = "UIS{Image:SunkEdge/Image#1,4}"
+# border = { 4, 4, 3, 1 }
+# stretch = TRUE
+# }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "viewportbin"
+ file = "greybg.png"
+ border = { 0, 0, 0, 0 }
+ stretch = TRUE
+ }
+#
+# Arrows for all occasions
+#
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_up.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = UP
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_rollover_up.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = UP
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_in_up.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = UP
+ }
+
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_down.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = DOWN
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_rollover_down.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = DOWN
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_in_down.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = DOWN
+ }
+
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_left.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = LEFT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_rollover_left.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = LEFT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_in_left.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = LEFT
+ }
+
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = NORMAL
+ file = "arrow_right.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = RIGHT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ state = PRELIGHT
+ file = "arrow_rollover_right.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+
+ arrow_direction = RIGHT
+ }
+ image
+ {
+ function = ARROW
+ recolorable = TRUE
+ shadow = IN
+ file = "arrow_in_right.png"
+ stretch = TRUE
+ border = { 5, 5, 5, 5 }
+ arrow_direction = RIGHT
+ }
+
+#
+# Hline and Vline widgets
+#
+ image
+ {
+ function = HLINE
+ recolorable = TRUE
+ file = "hline.png"
+ stretch = TRUE
+ }
+ image
+ {
+ function = VLINE
+ recolorable = TRUE
+ file = "vline.png"
+ border = { 1, 1, 0, 0 }
+ stretch = TRUE
+ }
+#
+# Check marks
+#
+ image
+ {
+ function = CHECK
+ recolorable = TRUE
+ shadow = OUT
+ overlay_file = "check_out.png"
+ overlay_stretch = FALSE
+ }
+ image
+ {
+ function = CHECK
+ recolorable = TRUE
+ shadow = IN
+ overlay_file = "check_in.png"
+ overlay_stretch = FALSE
+ }
+#
+# Option marks
+#
+ image
+ {
+ function = OPTION
+ recolorable = TRUE
+ shadow = OUT
+ overlay_file = "radio_out.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ }
+ image
+ {
+ function = OPTION
+ recolorable = TRUE
+ shadow = IN
+ overlay_file = "radio_in.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ }
+#
+# The "tab" on the OptionMenu
+#
+ image
+ {
+ function = TAB
+ recolorable = TRUE
+ overlay_file = "pulldown_indicator.png"
+ overlay_stretch = FALSE
+ }
+#
+# Fun with Scrollbars
+#
+ image
+ {
+ function = SLIDER
+ recolorable = TRUE
+ file = "slider_horizontal.png"
+ border = { 1, 1, 1, 1 }
+ stretch = TRUE
+ orientation = HORIZONTAL
+ }
+ image
+ {
+ function = SLIDER
+ recolorable = TRUE
+ file = "slider_vertical.png"
+ border = { 1, 1, 1, 1 }
+ stretch = TRUE
+ orientation = VERTICAL
+ }
+#
+# The handle on Handleboxes
+#
+ image
+ {
+ function = HANDLE
+ recolorable = TRUE
+ file = "menu.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ overlay_file = "handle_vertical.png"
+ border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ orientation = VERTICAL
+ }
+ image
+ {
+ function = HANDLE
+ recolorable = TRUE
+ file = "menu.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ overlay_file = "handle_horizontal.png"
+ overlay_border = { 0, 0, 0, 0 }
+ overlay_stretch = FALSE
+ orientation = HORIZONTAL
+ }
+#
+# The background for entry widgets
+#
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ state = INSENSITIVE
+ detail = "entry_bg"
+ file = "entry.png"
+ stretch = TRUE
+ }
+ image
+ {
+ function = FLAT_BOX
+ recolorable = TRUE
+ detail = "entry_bg"
+ file = "entry.png"
+ stretch = TRUE
+ }
+#
+# How to draw the focus around a widget
+#
+ #image
+ #{
+ #function = FOCUS
+ #recolorable = TRUE
+ #overlay_file = "focus.png"
+ #overlay_border = { 4, 4, 4, 4 }
+ #overlay_stretch = TRUE
+ #}
+#
+# How to draw shadows in general
+#
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = IN
+ file = "shadow_in.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = OUT
+ file = "shadow_out.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = ETCHED_IN
+ file = "frame_box_inset.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+ image
+ {
+ function = SHADOW
+ recolorable = TRUE
+ shadow = ETCHED_OUT
+ file = "frame_box_outset.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ }
+#
+# How to draw shadows with a gap on one side
+#
+ image
+ {
+ function = SHADOW_GAP
+ recolorable = TRUE
+ file = "frame_box_inset.png"
+ border = { 2, 2, 2, 2 }
+ stretch = TRUE
+ gap_start_file = "frame_gap_top_start.png"
+ gap_start_border= { 2, 0, 0, 0 }
+ gap_end_file = "frame_gap_top_end.png"
+ gap_end_border = { 0, 2, 0, 0 }
+ gap_side = TOP
+ }
+ image
+ {
+ function = BOX
+ recolorable = TRUE
+ file = "notebook.png"
+ border = { 3, 3, 3, 3 }
+ stretch = TRUE
+ }
+ }
+}
+
+class "GtkWidget" style "default"
+
+class "GtkRange" style "range"
+
+style "range"
+{
+ engine "pixmap" {
+ image
+ {
+ function = SLIDER
+ orientation = HORIZONTAL
+ file = "slider_horizontal.png"
+ }
+ image
+ {
+ function = SLIDER
+ orientation = VERTICAL
+ file = "slider_vertical.png"
+ }
+ image
+ {
+ function = BOX
+ detail = "trough"
+ orientation = HORIZONTAL
+ file = "trough.png"
+ border = { 4, 4, 3, 1 }
+ }
+ image
+ {
+ function = BOX
+ detail = "trough"
+ orientation = HORIZONTAL
+ file = "trough.png"
+ border = { 4, 4, 3, 1 }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_horizontal.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_horizontal.png
new file mode 100644
index 0000000..b21b122
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_horizontal.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_vertical.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_vertical.png
new file mode 100644
index 0000000..b21b122
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/handle_vertical.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menu_border.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menu_border.png
new file mode 100644
index 0000000..b1981f1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menu_border.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menuitem.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menuitem.png
new file mode 100644
index 0000000..0a244b0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/menuitem.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu.png
new file mode 100644
index 0000000..e50e24c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_disabled.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_disabled.png
new file mode 100644
index 0000000..9913d6d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_disabled.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_rollover.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_rollover.png
new file mode 100644
index 0000000..7c83aed
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/optionmenu_rollover.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress.png
new file mode 100644
index 0000000..34faed0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress_track.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress_track.png
new file mode 100644
index 0000000..14a2757
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/progress_track.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_in.png
new file mode 100644
index 0000000..b7f5f49
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_out.png
new file mode 100644
index 0000000..7f22605
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/radio_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_htrough.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_htrough.png
new file mode 100644
index 0000000..57deb9a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_htrough.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_vtrough.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_vtrough.png
new file mode 100644
index 0000000..c095cfb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/scrollbar_vtrough.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider.png
new file mode 100644
index 0000000..49c896d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_disabled.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_disabled.png
new file mode 100644
index 0000000..49c896d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_disabled.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_horizontal.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_horizontal.png
new file mode 100644
index 0000000..a5cc254
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_horizontal.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_vertical.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_vertical.png
new file mode 100644
index 0000000..5fc1f9e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/slider_vertical.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_horizontal.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_horizontal.png
new file mode 100644
index 0000000..e3537eb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_horizontal.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_horizontal.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_horizontal.png
new file mode 100644
index 0000000..f23a594
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_horizontal.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_vertical.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_vertical.png
new file mode 100644
index 0000000..bc9d33c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_rollover_vertical.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_vertical.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_vertical.png
new file mode 100644
index 0000000..bc9d33c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/sliderthumb_vertical.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_downarrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_downarrow.png
new file mode 100644
index 0000000..f787119
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_downarrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_hhandle.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_hhandle.png
new file mode 100644
index 0000000..1d6947f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_hhandle.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_leftarrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_leftarrow.png
new file mode 100644
index 0000000..5fa371d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_leftarrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_rightarrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_rightarrow.png
new file mode 100644
index 0000000..7462c08
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_rightarrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_uparrow.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_uparrow.png
new file mode 100644
index 0000000..bc41a5b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_uparrow.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_vhandle.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_vhandle.png
new file mode 100644
index 0000000..3599ab4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/splitpane_vhandle.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active.png
new file mode 100644
index 0000000..a8b8d57
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active_bottom.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active_bottom.png
new file mode 100644
index 0000000..ce8487b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_active_bottom.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_border.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_border.png
new file mode 100644
index 0000000..5d99db8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/tab_border.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_in.png
new file mode 100644
index 0000000..9d5692a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_out.png
new file mode 100644
index 0000000..f99aabb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_disabled_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_in.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_in.png
new file mode 100644
index 0000000..53a7de6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_in.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_out.png
new file mode 100644
index 0000000..f2aa268
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_rollover_out.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_rollover_out.png
new file mode 100644
index 0000000..84fd54f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/toggle_rollover_out.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/trough.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/trough.png
new file mode 100644
index 0000000..49c896d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/gtk/trough.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Computer.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Computer.gif
new file mode 100644
index 0000000..0428956
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Computer.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Default.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Default.gif
new file mode 100644
index 0000000..6768828
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Default.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/DetailsView.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/DetailsView.gif
new file mode 100644
index 0000000..4011722
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/DetailsView.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Error.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Error.gif
new file mode 100644
index 0000000..f2e9de7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Error.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/File.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/File.gif
new file mode 100644
index 0000000..0192fce
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/File.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/FloppyDrive.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/FloppyDrive.gif
new file mode 100644
index 0000000..49f8a15
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/FloppyDrive.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HardDrive.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HardDrive.gif
new file mode 100644
index 0000000..4539656
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HardDrive.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HomeFolder.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HomeFolder.gif
new file mode 100644
index 0000000..c2d7401
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/HomeFolder.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Inform.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Inform.gif
new file mode 100644
index 0000000..648c957
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Inform.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/ListView.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/ListView.gif
new file mode 100644
index 0000000..c169842
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/ListView.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/NewFolder.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/NewFolder.gif
new file mode 100644
index 0000000..14ced04
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/NewFolder.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Question.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Question.gif
new file mode 100644
index 0000000..7db3f11
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Question.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeClosed.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeClosed.gif
new file mode 100644
index 0000000..f876988
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeClosed.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeOpen.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeOpen.gif
new file mode 100644
index 0000000..dda4c83
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/TreeOpen.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/UpFolder.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/UpFolder.gif
new file mode 100644
index 0000000..babb6d1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/UpFolder.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Warn.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Warn.gif
new file mode 100644
index 0000000..2388e0f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Warn.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Window.gif b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Window.gif
new file mode 100644
index 0000000..48161fe
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/icons/Window.gif
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close.png
new file mode 100644
index 0000000..b00390f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_disabled.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_disabled.png
new file mode 100644
index 0000000..5a9a411
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_disabled.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_down.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_down.png
new file mode 100644
index 0000000..f4ac626
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_down.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_rollover.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_rollover.png
new file mode 100644
index 0000000..468192a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/close_rollover.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/kde.themerc b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/kde.themerc
new file mode 100644
index 0000000..0d84caf
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/kde.themerc
@@ -0,0 +1,90 @@
+[General]
+name=Template
+author=MsStylesToSkinLF
+email=noone@isinnocent.com
+homepage=http://www.noone.com
+description=Template
+version=1.0
+
+[Panel]
+background=background.bmp
+
+[Colors]
+desktop=116 120 129
+
+background=228 231 237
+foreground=0 0 0
+
+activeBackground=228 231 237
+activeForeground=0 0 0
+
+inactiveBackground=228 231 237
+inactiveForeground=116 120 129
+
+activeBlend=53,99,144
+inactiveBlend=192,192,192
+
+selectBackground=139 144 150
+selectForeground=255 255 255
+
+contrast=7
+
+windowBackground=255 255 255
+windowForeground=13 13 13
+
+[Window Titlebar]
+CloseButton=close.png
+CloseRolloverButton=close_rollover.png
+CloseDownButton=close_down.png
+CloseInactiveButton=close_disabled.png
+
+MaximizeButton=maximize.png
+MaximizeRolloverButton=maximize_rollover.png
+MaximizeDownButton=maximize_down.png
+MaximizeInactiveButton=maximize_disabled.png
+
+MenuButton=menu.xpm
+
+MinimizeButton=minimize.png
+MinimizeRolloverButton=minimize_rollover.png
+MinimizeDownButton=minimize_down.png
+MinimizeInactiveButton=minimize_disabled.png
+
+StickyButton=sticky.xpm
+StickyDownButton=stickydown.xpm
+
+TitlebarPixmapActive=titlebar_selected.png
+TitlebarPixmapActiveBorder=80, 80, 0, 16
+TitlebarPixmapActiveLeft=
+TitlebarPixmapActiveRight=
+TitlebarPixmapActiveTop=
+TitlebarPixmapActiveBottom=
+TitlebarPixmapInactive=titlebar_unselected.png
+
+PixmapUnderTitleText=yes
+TitleFrameShaded=no
+TitleAlignment=middle
+TitleAbsolutePosition=yes
+
+[Window Border]
+shapePixmapTop=
+shapePixmapBottom=window_bottom.png
+shapePixmapLeft=window_left.png
+shapePixmapRight=window_right.png
+shapePixmapTopLeft=window_topleft.png
+shapePixmapTopRight=window_topright.png
+shapePixmapBottomLeft=window_bottomleft.png
+shapePixmapBottomRight=window_bottomright.png
+
+[Window Button Layout]
+ButtonA=Off
+ButtonB=Off
+ButtonC=Off
+ButtonD=Close
+ButtonE=Maximize
+ButtonF=Iconify
+
+[Sounds]
+WindowShadeDown=RollUp.wav
+WindowShadeUp=RollUp.wav
+WindowClose=Close.wav
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize.png
new file mode 100644
index 0000000..b00390f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_disabled.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_disabled.png
new file mode 100644
index 0000000..5a9a411
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_disabled.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_down.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_down.png
new file mode 100644
index 0000000..54b4458
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_down.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_rollover.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_rollover.png
new file mode 100644
index 0000000..d8e6e5e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/maximize_rollover.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize.png
new file mode 100644
index 0000000..b00390f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_disabled.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_disabled.png
new file mode 100644
index 0000000..5a9a411
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_disabled.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_down.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_down.png
new file mode 100644
index 0000000..d4773fd
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_down.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_rollover.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_rollover.png
new file mode 100644
index 0000000..1dc1796
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/minimize_rollover.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_selected.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_selected.png
new file mode 100644
index 0000000..2b61dd3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_selected.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_unselected.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_unselected.png
new file mode 100644
index 0000000..cb8ac09
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/titlebar_unselected.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottom.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottom.png
new file mode 100644
index 0000000..24ef2ed
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottom.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomleft.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomleft.png
new file mode 100644
index 0000000..ade162b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomleft.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomright.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomright.png
new file mode 100644
index 0000000..1450e8e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_bottomright.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_left.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_left.png
new file mode 100644
index 0000000..95c4d09
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_left.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_right.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_right.png
new file mode 100644
index 0000000..3092cdf
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_right.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topleft.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topleft.png
new file mode 100644
index 0000000..2919eb2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topleft.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topright.png b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topright.png
new file mode 100644
index 0000000..c26cb32
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/kde/window_topright.png
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/skinlf-themepack.xml b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/skinlf-themepack.xml
new file mode 100644
index 0000000..020b01e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/themepacks/toxicthemepack/skinlf-themepack.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<skinlf-themepack require="1.2.9">
+
+ <!--
+ Information about this themepack
+ -->
+ <property name="skin.name"
+ value="Alluminium Alloy / Toxic"/>
+ <property name="skin.description"
+ value="Graphics and images taken from Alluminium Alloy Visual Style of Francisco Ocasio (KOL)"/>
+ <property name="skin.url"
+ value="http://www.studiotwentyeight.com"/>
+
+ <property name="JDesktopPane.backgroundEnabled" value="false" />
+ <property name="JSplitPane.alternateUI" value="true" />
+
+ <!--
+ SkinLF custom properties
+ -->
+ <font name="Global" value="SansSerif,0,11"/>
+
+ <!--
+ UIManager properties
+ -->
+ <property name="PopupMenu.border" type="LineBorder" thickness="1" padding="2" color="#A6AAB3" />
+ <property name="TextField.border" type="LineBorder" thickness="1" padding="2" color="#A6AAB3" />
+ <property name="PasswordField.border" type="LineBorder" thickness="1" padding="2" color="#A6AAB3" />
+ <icon name="InternalFrame.icon" value="icons/Window.gif"/>
+
+ <icon name="FileView.directoryIcon" value="icons/TreeClosed.gif"/>
+ <icon name="FileView.fileIcon" value="icons/File.gif"/>
+ <icon name="FileView.computerIcon" value="icons/Computer.gif"/>
+ <icon name="FileView.hardDriveIcon" value="icons/HardDrive.gif"/>
+ <icon name="FileView.floppyDriveIcon" value="icons/FloppyDrive.gif"/>
+
+ <icon name="FileChooser.newFolderIcon" value="icons/TreeClosed.gif"/>
+ <icon name="FileChooser.upFolderIcon" value="icons/UpFolder.gif"/>
+ <icon name="FileChooser.homeFolderIcon" value="icons/HomeFolder.gif"/>
+
+ <icon name="Tree.openIcon" value="icons/TreeOpen.gif"/>
+ <icon name="Tree.closedIcon" value="icons/TreeClosed.gif"/>
+ <icon name="Tree.leafIcon" value="icons/Default.gif"/>
+
+ <icon name="OptionPane.errorIcon" value="icons/Error.gif"/>
+ <icon name="OptionPane.informationIcon" value="icons/Inform.gif"/>
+ <icon name="OptionPane.warningIcon" value="icons/Warn.gif"/>
+ <icon name="OptionPane.questionIcon" value="icons/Question.gif"/>
+
+ <!--
+ Skin Definition
+ -->
+ <skin>
+ <skin url="gtk/gtkrc"></skin>
+ <skin url="kde/kde.themerc"></skin>
+ </skin>
+
+</skinlf-themepack>
diff --git a/src/net/java/sip/communicator/impl/history/Activator.java b/src/net/java/sip/communicator/impl/history/Activator.java
new file mode 100644
index 0000000..fab1c24
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/Activator.java
@@ -0,0 +1,13 @@
+package net.java.sip.communicator.impl.history;
+
+import org.ungoverned.gravity.servicebinder.GenericActivator;
+
+/**
+ * Invoke "Service Binder" to parse the service XML and register
+ * all services.
+ *
+ * @author Alexander Pelov
+ */
+public class Activator extends GenericActivator {
+
+}
diff --git a/src/net/java/sip/communicator/impl/history/DBStructSerializer.java b/src/net/java/sip/communicator/impl/history/DBStructSerializer.java
new file mode 100644
index 0000000..adde8b9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/DBStructSerializer.java
@@ -0,0 +1,237 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.history;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+
+import javax.xml.parsers.DocumentBuilder;
+
+import net.java.sip.communicator.service.history.History;
+import net.java.sip.communicator.service.history.HistoryID;
+import net.java.sip.communicator.service.history.records.HistoryRecordStructure;
+import net.java.sip.communicator.service.history.records.TextType;
+import net.java.sip.communicator.util.EnumerationBase;
+import net.java.sip.communicator.util.xml.XMLUtils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * @author Alexander Pelov
+ */
+public class DBStructSerializer {
+
+ private HistoryServiceImpl historyService;
+
+ public DBStructSerializer(HistoryServiceImpl historyService) {
+ this.historyService = historyService;
+ }
+
+ public void writeHistory(File dbDatFile, History history)
+ throws IOException
+ {
+ DocumentBuilder builder = this.historyService.getDocumentBuilder();
+ Document doc = builder.newDocument();
+
+ Element root = doc.createElement("dbstruct");
+ root.setAttribute("version", "1.0");
+
+ Element structure = this.createStructureTag(doc,
+ history.getHistoryRecordsStructure());
+ Element id = this.createIDTag(doc, history.getID());
+
+ root.appendChild(structure);
+ root.appendChild(id);
+
+ doc.appendChild(root);
+
+ XMLUtils.writeXML(doc, dbDatFile);
+ }
+
+ private Element createIDTag(Document doc, HistoryID historyID) {
+ Element idroot = doc.createElement("id");
+ Element current = idroot;
+
+ String[] idelements = historyID.getID();
+ for(int i = 0; i < idelements.length; i++) {
+ Element idnode = doc.createElement("component");
+ idnode.setAttribute("value", idelements[i]);
+
+ current.appendChild(idnode);
+ current = idnode;
+ }
+
+ return idroot;
+ }
+
+ private Element createStructureTag(Document doc,
+ HistoryRecordStructure recordStructure)
+ {
+ Element structure = doc.createElement("structure");
+ String[] propertyNames = recordStructure.getPropertyNames();
+ TextType[] propertyTypes = recordStructure.getValueTypes();
+ int count = recordStructure.getPropertyCount();
+ for(int i = 0; i < count; i++) {
+ Element property = doc.createElement("property");
+ property.setAttribute("name", propertyNames[i]);
+ property.setAttribute("type", propertyTypes[i].toString());
+
+ structure.appendChild(property);
+ }
+
+ return structure;
+ }
+
+ /**
+ * This method parses an XML file, and returns a History object created
+ * with the information from it. The parsing is non-validating, so if a
+ * malformed XML is passed the results are undefined.
+ * The file should be with the following structure:
+ *
+ * <dbstruct version="1.0">
+ * <id value="idcomponent1">
+ * <id value="idcomponent2">
+ * <id value="idcomponent3"/>
+ * </id>
+ * </id>
+ *
+ * <structure>
+ * <property name="propertyName" type="textType" />
+ * <property name="propertyName" type="textType" />
+ * <property name="propertyName" type="textType" />
+ * </structure>
+ * </dbstruct>
+ *
+ * @param dbDatFile The file to be parsed.
+ * @return A History object corresponding to this dbstruct file.
+ * @throws SAXException Thrown if an error occurs during XML parsing.
+ * @throws IOException Thrown if an IO error occurs.
+ * @throws ParseException Thrown if there is error in the XML data format.
+ */
+ public History loadHistory(File dbDatFile)
+ throws SAXException, IOException, ParseException
+ {
+ DocumentBuilder builder = historyService.getDocumentBuilder();
+ Document doc = builder.parse(dbDatFile);
+
+ Node root = doc.getFirstChild();
+ HistoryID id = loadID(root);
+ HistoryRecordStructure structure = loadStructure(root);
+
+ return new HistoryImpl(id, dbDatFile.getParentFile(),
+ structure, historyService);
+ }
+
+ /**
+ * This method parses a "structure" tag and returns the corresponging
+ * HistoryRecordStructure.
+ *
+ * @throws ParseException Thrown if there is no structure tag.
+ */
+ private HistoryRecordStructure loadStructure(Node root)
+ throws ParseException
+ {
+ Element structNode = findElement(root, "structure");
+ if(structNode == null) {
+ throw new ParseException("There is not structure tag defined!", 0);
+ }
+
+ NodeList nodes = structNode.getChildNodes();
+ int count = nodes.getLength();
+
+ ArrayList propertyNames = new ArrayList(count);
+ ArrayList propertyTypes = new ArrayList(count);
+
+ for(int i = 0; i < count; i++) {
+ Node node = nodes.item(i);
+ if(node.getNodeType() == Node.ELEMENT_NODE &&
+ "property".equals(node.getNodeName()))
+ {
+ Element parameter = (Element) node;
+ String paramName = parameter.getAttribute("name");
+ String paramType = parameter.getAttribute("type");
+
+ if(paramName == null) {
+ continue;
+ }
+
+ TextType type = (TextType)EnumerationBase.fromString(
+ TextType.class, paramType);
+ if(type == null) {
+ type = HistoryRecordStructure.DEFAULT_TEXT_TYPE;
+ }
+
+ propertyNames.add(paramName);
+ propertyTypes.add(type);
+ }
+ }
+
+ String[] names = new String[propertyNames.size()];
+ TextType[] types = new TextType[propertyTypes.size()];
+
+ propertyNames.toArray(names);
+ propertyTypes.toArray(types);
+
+ return new HistoryRecordStructure(names, types);
+ }
+
+ private HistoryID loadID(Node parent) throws ParseException {
+ Element idnode = findElement(parent, "id");
+ ArrayList al = loadID(new ArrayList(), idnode);
+
+ String[] id = new String[al.size()];
+ al.toArray(id);
+
+ return HistoryID.createFromID(id);
+ }
+
+ private ArrayList loadID(ArrayList loadedIDs, Node parent)
+ throws ParseException
+ {
+ Element node = findElement(parent, "component");
+ if(node != null) {
+ String idValue = node.getAttribute("value");
+ if(idValue != null) {
+ loadedIDs.add(idValue);
+ } else {
+ throw new ParseException(
+ "There is an ID object without value.", 0);
+ }
+ }
+
+ return loadID(loadedIDs, node);
+ }
+
+ /**
+ * This method seraches through all children of a given node
+ * and returns the first with the name matching the given one.
+ * If no node is found, null is returned.
+ */
+ private Element findElement(Node parent, String name) {
+ Element retVal = null;
+ NodeList nodes = parent.getChildNodes();
+ int count = nodes.getLength();
+
+ for(int i = 0; i < count; i++) {
+ Node node = nodes.item(i);
+ if(node.getNodeType() == Node.ELEMENT_NODE &&
+ name.equals(node.getNodeName()))
+ {
+ retVal = (Element)node;
+ break;
+ }
+ }
+ return retVal;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/history/HistoryImpl.java b/src/net/java/sip/communicator/impl/history/HistoryImpl.java
new file mode 100644
index 0000000..1dea20d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/HistoryImpl.java
@@ -0,0 +1,197 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.history;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.Iterator;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.xml.parsers.DocumentBuilder;
+
+import net.java.sip.communicator.service.history.History;
+import net.java.sip.communicator.service.history.HistoryID;
+import net.java.sip.communicator.service.history.HistoryReader;
+import net.java.sip.communicator.service.history.HistoryWriter;
+import net.java.sip.communicator.service.history.records.HistoryRecordStructure;
+import net.java.sip.communicator.util.Assert;
+import net.java.sip.communicator.util.Logger;
+import net.java.sip.communicator.util.xml.XMLUtils;
+
+import org.w3c.dom.Document;
+
+/**
+ * @author Alexander Pelov
+ */
+public class HistoryImpl implements History {
+
+ private static Logger log = Logger.getLogger(HistoryImpl.class);
+
+ private HistoryID id;
+ private HistoryRecordStructure historyRecordStructure;
+ private HistoryServiceImpl historyServiceImpl;
+
+ private File directory;
+ private HistoryReader reader;
+ private HistoryWriter writer;
+
+ private SortedMap historyDocuments = new TreeMap();
+
+ protected HistoryImpl(
+ HistoryID id,
+ File directory,
+ HistoryRecordStructure historyRecordStructure,
+ HistoryServiceImpl historyServiceImpl)
+ {
+ try {
+ log.logEntry();
+
+ Assert.assertNonNull(historyServiceImpl, "The historyServiceImpl should be non-null.");
+ Assert.assertNonNull(id, "The ID should be non-null.");
+ Assert.assertNonNull(historyRecordStructure, "The structure should be non-null.");
+
+ this.id = id;
+ this.directory = directory;
+ this.historyServiceImpl = historyServiceImpl;
+ this.historyRecordStructure = historyRecordStructure;
+ this.reader = null;
+ this.writer = null;
+
+ this.reloadDocumentList();
+ } finally {
+ log.logExit();
+ }
+ }
+
+ public HistoryID getID() {
+ return this.id;
+ }
+
+ public HistoryRecordStructure getHistoryRecordsStructure() {
+ return this.historyRecordStructure;
+ }
+
+ public HistoryReader getReader() {
+ if(this.reader == null) {
+ this.reader = new HistoryReaderImpl(this);
+ }
+
+ return this.reader;
+ }
+
+ public HistoryWriter getWriter() {
+ if(this.writer == null) {
+ this.writer = new HistoryWriterImpl(this);
+ }
+
+ return this.writer;
+ }
+
+ protected HistoryServiceImpl getHistoryServiceImpl() {
+ return this.historyServiceImpl;
+ }
+
+ private void reloadDocumentList() {
+ synchronized(this.historyDocuments) {
+ this.historyDocuments.clear();
+
+ File[] files = this.directory.listFiles();
+ Assert.assertNonNull(files, "The list of files should be non-null.");
+
+ for(int i = 0; i < files.length; i++) {
+ if(!files[i].isDirectory()) {
+ this.historyDocuments.put(files[i].getName(), files[i]);
+ }
+ }
+ }
+ }
+
+
+ protected Document createDocument(String filename) {
+ Document retVal = null;
+
+ synchronized(this.historyDocuments) {
+ if(this.historyDocuments.containsKey(filename)) {
+ retVal = getDocumentForFile(filename);
+ } else {
+ retVal = this.historyServiceImpl.getDocumentBuilder().newDocument();
+ retVal.appendChild(retVal.createElement("history"));
+
+ this.historyDocuments.put(filename, retVal);
+ }
+ }
+
+ return retVal;
+ }
+
+ protected void writeFile(String filename)
+ throws InvalidParameterException, IOException
+ {
+ File file = new File(this.directory, filename);
+
+ synchronized(this.historyDocuments) {
+ if(!this.historyDocuments.containsKey(filename)) {
+ throw new InvalidParameterException("The requested " +
+ "filename does not exist in the document list.");
+ }
+
+ Object obj = this.historyDocuments.get(filename);
+ if(obj instanceof Document) {
+ Document doc = (Document)obj;
+
+ synchronized(doc) {
+ XMLUtils.writeXML(doc, file);
+ }
+ }
+ }
+ }
+
+ protected Iterator getFileList() {
+ return this.historyDocuments.keySet().iterator();
+ }
+
+ protected Document getDocumentForFile(String filename)
+ throws InvalidParameterException, RuntimeException
+ {
+ Document retVal = null;
+
+ synchronized(this.historyDocuments) {
+ if(!this.historyDocuments.containsKey(filename)) {
+ throw new InvalidParameterException("The requested " +
+ "filename does not exist in the document list.");
+ }
+
+ Object obj = this.historyDocuments.get(filename);
+ if(obj instanceof Document) {
+ // Document already loaded. Use it directly
+ retVal = (Document)obj;
+ } else if(obj instanceof File) {
+ File file = (File)obj;
+
+ DocumentBuilder builder = this.historyServiceImpl.getDocumentBuilder();
+
+ try {
+ retVal = builder.parse(file);
+ } catch (Exception e) {
+ throw new RuntimeException("Error occured while " +
+ "parsing XML document.", e);
+ }
+
+ // Cache the loaded document for reuse
+ this.historyDocuments.put(filename, retVal);
+ } else {
+ Assert.fail("Internal error - the data type " +
+ "should be either Document or File.");
+ }
+ }
+
+ return retVal;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java b/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java
new file mode 100644
index 0000000..dc801d4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java
@@ -0,0 +1,163 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.history;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import net.java.sip.communicator.service.history.HistoryReader;
+import net.java.sip.communicator.service.history.QueryResultSet;
+import net.java.sip.communicator.service.history.DefaultQueryResultSet;
+import net.java.sip.communicator.service.history.records.HistoryRecord;
+import net.java.sip.communicator.util.BidirectionalIterator;
+
+import org.jaxen.JaxenException;
+import org.jaxen.Navigator;
+import org.jaxen.XPath;
+import org.jaxen.dom.DocumentNavigator;
+import org.jaxen.saxpath.SAXPathException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author Alexander Pelov
+ */
+public class HistoryReaderImpl implements HistoryReader {
+
+ private HistoryImpl historyImpl;
+
+ protected HistoryReaderImpl(HistoryImpl historyImpl) {
+ this.historyImpl = historyImpl;
+ }
+
+ public QueryResultSet findByStartDate(Date startDate) throws RuntimeException {
+ String expr = "/history/record[@timestamp>"+startDate.getTime()+"]";
+
+ return this.findByXpath(expr);
+ }
+
+ public QueryResultSet findByEndDate(Date endDate) throws RuntimeException {
+ String expr = "/history/record[@timestamp<"+endDate.getTime()+"]";
+
+ return this.findByXpath(expr);
+ }
+
+ public QueryResultSet findByPeriod(Date startDate, Date endDate)
+ throws RuntimeException {
+ String expr = "/history/record[@timestamp>"+startDate.getTime()+"]" +
+ "[@timestamp<"+endDate.getTime()+"]";
+
+ return this.findByXpath(expr);
+ }
+
+ public QueryResultSet findByKeyword(String keyword) throws RuntimeException {
+ return findByKeywords(new String[] {keyword});
+ }
+
+ public QueryResultSet findByKeywords(String[] keywords)
+ throws RuntimeException {
+
+ String expr = "/history/record";
+ for(int i = 0; i < keywords.length; i++) {
+ expr += "[contains(*/text(),'"+keywords[i]+"')]";
+ }
+
+ return this.findByXpath(expr);
+ }
+
+ public QueryResultSet findByText(Date startDate, Date endDate,
+ String[] keywords) throws UnsupportedOperationException
+ {
+ String expr = "/history/record[@timestamp>"+startDate.getTime()+"]" +
+ "[@timestamp<"+endDate.getTime()+"]";
+ for(int i = 0; i < keywords.length; i++) {
+ expr += "[contains(*/text(),'"+keywords[i]+"')]";
+ }
+
+ return this.findByXpath(expr);
+ }
+
+ public BidirectionalIterator bidirectionalIterator() {
+ String expr = "/history/record";
+
+ return this.findByXpath(expr);
+ }
+
+ public Iterator iterator() {
+ return this.bidirectionalIterator();
+ }
+
+
+ private QueryResultSet findByXpath(String xpathExpression) {
+ Vector vect = new Vector();
+
+ Iterator filelist = this.historyImpl.getFileList();
+
+ Navigator navigator = DocumentNavigator.getInstance();
+ XPath xpath;
+
+ try {
+ xpath = navigator.parseXPath(xpathExpression);
+ } catch (SAXPathException e) {
+ throw new RuntimeException(e);
+ }
+
+ while(filelist.hasNext()) {
+ String filename = (String)filelist.next();
+ Document doc = this.historyImpl.getDocumentForFile(filename);
+
+ List nodes;
+ try {
+ nodes = xpath.selectNodes(doc);
+ } catch (JaxenException e) {
+ throw new RuntimeException(e);
+ }
+
+ Iterator i = nodes.iterator();
+ while(i.hasNext()) {
+ Node node = (Node)i.next();
+ NodeList propertyNodes = node.getChildNodes();
+
+ String ts = node.getAttributes().getNamedItem("timestamp").getNodeValue();
+ Date timestamp = new Date(Long.parseLong(ts));
+
+ ArrayList nameVals = new ArrayList();
+
+ int len = propertyNodes.getLength();
+ for(int j = 0; j < len; j++) {
+ Node propertyNode = propertyNodes.item(j);
+ if(propertyNode.getNodeType() == Node.ELEMENT_NODE) {
+ nameVals.add(propertyNode.getNodeName());
+ // Get nested TEXT node's value
+ nameVals.add(propertyNode.getFirstChild().getNodeValue());
+ }
+ }
+
+ String[] propertyNames = new String[nameVals.size()/2];
+ String[] propertyValues = new String[propertyNames.length];
+ for(int j = 0; j < propertyNames.length; j++) {
+ propertyNames[j] = (String)nameVals.get(j*2);
+ propertyValues[j] = (String)nameVals.get(j*2+1);
+ }
+
+ HistoryRecord record = new HistoryRecord(
+ propertyNames,
+ propertyValues,
+ timestamp);
+
+ vect.add(record);
+ }
+ }
+
+ return new DefaultQueryResultSet(vect);
+
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/history/HistoryServiceImpl.java b/src/net/java/sip/communicator/impl/history/HistoryServiceImpl.java
new file mode 100644
index 0000000..946aa9f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/HistoryServiceImpl.java
@@ -0,0 +1,255 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.history;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import net.java.sip.communicator.service.configuration.ConfigurationService;
+import net.java.sip.communicator.service.history.History;
+import net.java.sip.communicator.service.history.HistoryID;
+import net.java.sip.communicator.service.history.HistoryService;
+import net.java.sip.communicator.service.history.records.HistoryRecordStructure;
+import net.java.sip.communicator.service.resources.FileAccessService;
+import net.java.sip.communicator.util.Logger;
+
+/**
+ * @author Alexander Pelov
+ */
+public class HistoryServiceImpl implements HistoryService {
+
+ public static final String DATA_DIRECTORY = "history_ver1.0";
+
+ public static final String DATA_FILE = "dbstruct.dat";
+
+ /**
+ * The logger for this class.
+ */
+ private static Logger log = Logger
+ .getLogger(HistoryServiceImpl.class);
+
+ private Map histories = Collections.synchronizedMap(new HashMap());
+
+ private Collection loadedFiles = Collections.synchronizedCollection(
+ new Vector());
+
+ private ConfigurationService configurationService;
+
+ private FileAccessService fileAccessService;
+
+ private Object syncRoot_FileAccess = new Object();
+
+ private Object syncRoot_Config = new Object();
+
+ private DocumentBuilder builder;
+
+
+ public HistoryServiceImpl()
+ throws Exception
+ {
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ this.builder = factory.newDocumentBuilder();
+ }
+
+ public Iterator getExistingIDs() {
+ Vector vect = new Vector();
+ File histDir = null;
+ try {
+ histDir = this.fileAccessService.getPrivatePersistentDirectory
+ (DATA_DIRECTORY);
+ findDatFiles(vect, histDir);
+ } catch (Exception e) {
+ log.error("Error opening directory", e);
+ }
+
+ DBStructSerializer structParse = new DBStructSerializer(this);
+ int size = vect.size();
+ for(int i = 0; i < size; i++) {
+ File f = (File)vect.get(i);
+
+ synchronized(this.loadedFiles) {
+ if(!this.loadedFiles.contains(f)) {
+ synchronized(this.histories) {
+ try {
+ History hist = structParse.loadHistory(f);
+ if(!this.histories.containsKey(hist.getID())) {
+ this.histories.put(hist.getID(), hist);
+ }
+ } catch(Exception e) {
+ log.error("Could not load history from file: " +
+ f.getAbsolutePath(), e);
+ }
+ }
+ }
+ }
+ }
+
+ synchronized(this.histories) {
+ return this.histories.keySet().iterator();
+ }
+ }
+
+ public boolean isHistoryExisting(HistoryID id) {
+ synchronized (this.histories) {
+ return this.histories.containsKey(id);
+ }
+ }
+
+ public History getHistory(HistoryID id) throws IllegalArgumentException {
+ History retVal = null;
+
+ synchronized(histories) {
+ if(histories.containsKey(id)) {
+ retVal = (History) histories.get(id);
+ } else {
+ throw new IllegalArgumentException(
+ "No history corresponds to the specified ID.");
+ }
+ }
+
+ return retVal;
+ }
+
+ public History createHistory(HistoryID id,
+ HistoryRecordStructure recordStructure)
+ throws IllegalArgumentException, IOException
+ {
+ History retVal = null;
+
+ synchronized(this.histories) {
+ if(this.histories.containsKey(id)) {
+ throw new IllegalArgumentException(
+ "There is already a history with the specified ID.");
+ } else {
+ File dir = this.createHistoryDirectories(id);
+ HistoryImpl history = new HistoryImpl(id, dir,
+ recordStructure, this);
+
+ File dbDatFile = new File(dir, HistoryServiceImpl.DATA_FILE);
+ DBStructSerializer dbss = new DBStructSerializer(this);
+ dbss.writeHistory(dbDatFile, history);
+
+ this.histories.put(id, history);
+ retVal = history;
+ }
+ }
+
+ return retVal;
+ }
+
+ protected FileAccessService getFileAccessService() {
+ return this.fileAccessService;
+ }
+
+ protected DocumentBuilder getDocumentBuilder() {
+ return builder;
+ }
+
+ private void findDatFiles(Vector vect, File directory) {
+ File[] files = directory.listFiles();
+ for(int i = 0; i < files.length; i++) {
+ if(files[i].isDirectory()) {
+ findDatFiles(vect, files[i]);
+ } else if(DATA_FILE.equalsIgnoreCase(files[i].getName())) {
+ vect.add(files[i]);
+ }
+ }
+ }
+
+ private File createHistoryDirectories(HistoryID id) throws IOException {
+ String[] idComponents = id.getID();
+ String[] dirs = new String[idComponents.length+1];
+ dirs[0] = "history";
+ System.arraycopy(idComponents, 0, dirs, 1, dirs.length-1);
+
+ File directory = null;
+ try {
+ directory = this.fileAccessService
+ .getPrivatePersistentDirectory(dirs);
+ } catch (Exception e) {
+ throw (IOException)new IOException(
+ "Could not create history due to file system error")
+ .initCause(e);
+ }
+
+ if(!directory.exists() && !directory.mkdirs()) {
+ throw new IOException(
+ "Could not create requested history service files:" +
+ directory.getAbsolutePath());
+ }
+
+ return directory;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Set the configuration service.
+ *
+ * @param configurationService
+ */
+ public void setConfigurationService(
+ ConfigurationService configurationService)
+ {
+ synchronized(this.syncRoot_Config) {
+ this.configurationService = configurationService;
+ log.debug("New configuration service registered.");
+ }
+ }
+
+ /**
+ * Remove a configuration service.
+ *
+ * @param configurationService
+ */
+ public void unsetConfigurationService(
+ ConfigurationService configurationService)
+ {
+ synchronized(this.syncRoot_Config) {
+ if(this.configurationService == configurationService) {
+ this.configurationService = null;
+ log.debug("Configuration service unregistered.");
+ }
+ }
+ }
+
+ /**
+ * Set the file access service.
+ *
+ * @param fileAccessService
+ */
+ public void setFileAccessService(FileAccessService fileAccessService) {
+ synchronized(this.syncRoot_FileAccess) {
+ this.fileAccessService = fileAccessService;
+ log.debug("New file access service registered.");
+ }
+ }
+
+ /**
+ * Remove the file access service.
+ *
+ * @param fileAccessService
+ */
+ public void unsetFileAccessService(FileAccessService fileAccessService) {
+ synchronized(this.syncRoot_FileAccess) {
+ if(this.fileAccessService == fileAccessService) {
+ this.fileAccessService = null;
+ log.debug("File access service unregistered.");
+ }
+ }
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/history/HistoryWriterImpl.java b/src/net/java/sip/communicator/impl/history/HistoryWriterImpl.java
new file mode 100644
index 0000000..37828d2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/HistoryWriterImpl.java
@@ -0,0 +1,134 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.history;
+
+import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import net.java.sip.communicator.service.history.HistoryWriter;
+import net.java.sip.communicator.service.history.records.HistoryRecord;
+import net.java.sip.communicator.service.history.records.HistoryRecordStructure;
+import net.java.sip.communicator.util.Assert;
+
+/**
+ * @author Alexander Pelov
+ */
+public class HistoryWriterImpl implements HistoryWriter {
+
+ public static final int MAX_RECORDS_PER_FILE = 100;
+
+ private Object docCreateLock = new Object();
+ private Object docWriteLock = new Object();
+
+ private HistoryImpl historyImpl;
+ private String[] structPropertyNames;
+ private Document currentDoc = null;
+ private String currentFile = null;
+ private int currentDocElements = -1;
+
+ protected HistoryWriterImpl(HistoryImpl historyImpl) {
+ this.historyImpl = historyImpl;
+
+ HistoryRecordStructure struct =
+ this.historyImpl.getHistoryRecordsStructure();
+ this.structPropertyNames = struct.getPropertyNames();
+ }
+
+ public void addRecord(HistoryRecord record) throws IOException {
+ this.addRecord(record.getPropertyNames(), record.getPropertyValues(),
+ record.getTimestamp());
+ }
+
+ public void addRecord(String[] propertyValues) throws IOException {
+ this.addRecord(structPropertyNames, propertyValues, new Date());
+ }
+
+ private void addRecord(String[] propertyNames, String[] propertyValues, Date date)
+ throws InvalidParameterException, IOException
+ {
+ // Synchronized to assure that two concurent threads can insert records safely.
+ synchronized(docCreateLock) {
+ if(this.currentDoc == null || this.currentDocElements > MAX_RECORDS_PER_FILE) {
+ this.createNewDoc(date, this.currentDoc == null);
+ }
+ }
+
+ synchronized(this.currentDoc) {
+ Node root = this.currentDoc.getFirstChild();
+ synchronized(root) {
+ Element elem = this.currentDoc.createElement("record");
+ elem.setAttribute("timestamp", Long.toString(date.getTime()));
+
+ for(int i = 0; i < propertyNames.length; i++) {
+ Element propertyElement = this.currentDoc.createElement(propertyNames[i]);
+
+ Text value = this.currentDoc.createTextNode(propertyValues[i]);
+ propertyElement.appendChild(value);
+
+ elem.appendChild(propertyElement);
+ }
+
+ root.appendChild(elem);
+ this.currentDocElements++;
+ }
+ }
+
+ // write changes
+ synchronized(docWriteLock) {
+ this.historyImpl.writeFile(this.currentFile);
+ }
+ }
+
+ /**
+ * If no file is currently loaded loads the last opened file. If
+ * it does not exists or if the current file was set - create a
+ * new file.
+ *
+ * @param date
+ */
+ private void createNewDoc(Date date, boolean loadLastFile) {
+ boolean loaded = false;
+
+ if(loadLastFile) {
+ Iterator files = historyImpl.getFileList();
+
+ String file = null;
+ while(files.hasNext()) {
+ file = (String)files.next();
+ }
+
+ if(file != null) {
+ this.currentDoc = this.historyImpl.getDocumentForFile(file);
+ this.currentFile = file;
+ loaded = true;
+ }
+ }
+
+ if(!loaded) {
+ this.currentFile = Long.toString(date.getTime());
+ while(this.currentFile.length() < 8) {
+ this.currentFile = "0" + this.currentFile;
+ }
+ this.currentFile += ".xml";
+
+ this.currentDoc = this.historyImpl.createDocument(this.currentFile);
+ }
+
+ Assert.assertNonNull(this.currentDoc,
+ "There should be a current document created.");
+
+ this.currentDocElements = this.currentDoc.getFirstChild().getChildNodes().getLength();
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/history/history.manifest.mf b/src/net/java/sip/communicator/impl/history/history.manifest.mf
new file mode 100644
index 0000000..3b48970
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/history.manifest.mf
@@ -0,0 +1,33 @@
+Bundle-Activator: net.java.sip.communicator.impl.history.Activator
+Bundle-Name: History Service Provider
+Bundle-Description: A bundle that implements the history package.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.ungoverned.gravity.servicebinder,
+ org.osgi.framework,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.service.history,
+ net.java.sip.communicator.impl.history,
+ net.java.sip.communicator.service.history.query,
+ net.java.sip.communicator.service.history.records,
+ net.java.sip.communicator.service.protocol,
+ org.w3c.dom,
+ org.xml.sax,
+ javax.xml.parsers,
+ org.apache.xml.serializer,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.xml,
+ org.jaxen,
+ org.jaxen.dom,
+ org.jaxen.saxpath,
+Export-Package: net.java.sip.communicator.service.history,
+ net.java.sip.communicator.impl.history,
+ net.java.sip.communicator.service.history.query,
+ net.java.sip.communicator.service.history.records,
+ net.java.sip.communicator.service.protocol,
+Metadata-Location: /net/java/sip/communicator/impl/history/history.metadata.xml \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/history/history.metadata.xml b/src/net/java/sip/communicator/impl/history/history.metadata.xml
new file mode 100644
index 0000000..96f3d65
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/history/history.metadata.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<bundle>
+ <component class="net.java.sip.communicator.impl.history.HistoryServiceImpl">
+ <provides service="net.java.sip.communicator.service.history.HistoryService"/>
+
+ <requires service="net.java.sip.communicator.service.configuration.ConfigurationService"
+ filter=""
+ policy="static"
+ cardinality="1..1"
+ bind-method="setConfigurationService"
+ unbind-method="unsetConfigurationService" />
+
+ <requires service="net.java.sip.communicator.service.resources.FileAccessService"
+ filter=""
+ policy="static"
+ cardinality="1..1"
+ bind-method="setFileAccessService"
+ unbind-method="unsetFileAccessService" />
+
+ </component>
+</bundle>
diff --git a/src/net/java/sip/communicator/impl/media/Activator.java b/src/net/java/sip/communicator/impl/media/Activator.java
new file mode 100644
index 0000000..7f56273
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/Activator.java
@@ -0,0 +1,19 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.media;
+
+import org.ungoverned.gravity.servicebinder.GenericActivator;
+
+/**
+ * Invoke "Service Binder" to parse the service XML and register
+ * all services.
+ *
+ * @author Martin Andre
+ */
+public class Activator extends GenericActivator {
+
+}
diff --git a/src/net/java/sip/communicator/impl/media/MediaControl.java b/src/net/java/sip/communicator/impl/media/MediaControl.java
new file mode 100644
index 0000000..134b724
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/MediaControl.java
@@ -0,0 +1,144 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.media;
+
+import java.io.IOException;
+
+import javax.media.CaptureDeviceInfo;
+import javax.media.IncompatibleSourceException;
+import javax.media.Manager;
+import javax.media.MediaLocator;
+import javax.media.NoDataSourceException;
+import javax.media.protocol.CaptureDevice;
+import javax.media.protocol.DataSource;
+
+import net.java.sip.communicator.impl.media.configuration.MediaConfiguration;
+import net.java.sip.communicator.util.Logger;
+
+
+/**
+ * This class is intended to provide a generic way to control media package.
+ *
+ * @author Martin Andre
+ */
+public class MediaControl
+{
+ private Logger logger = Logger.getLogger(MediaConfiguration.class);
+
+ /**
+ * Our configuration helper.
+ */
+ private MediaConfiguration mediaConfiguration = null;
+
+ /**
+ * Capture devices
+ */
+ private CaptureDevice audioCaptureDevice = null;
+ private CaptureDevice videoCaptureDevice = null;
+ private DataSource avDataSource = null;
+
+ public MediaControl(MediaConfiguration mediaConfiguration)
+ {
+ this.mediaConfiguration = mediaConfiguration;
+ }
+
+ protected void openCaptureDevices()
+ {
+ // Init Capture devices
+ DataSource audioDataSource = null;
+ DataSource videoDataSource = null;
+ CaptureDeviceInfo audioDeviceInfo = null;
+ CaptureDeviceInfo videoDeviceInfo = null;
+
+ // audio device
+ audioDeviceInfo = mediaConfiguration.getAudioCaptureDevice();
+ if (audioDeviceInfo != null) {
+ audioDataSource = createDataSource(audioDeviceInfo.getLocator());
+ audioCaptureDevice = (CaptureDevice) audioDataSource;
+ }
+
+ // video device
+ videoDeviceInfo = mediaConfiguration.getVideoCaptureDevice();
+ if (videoDeviceInfo != null) {
+ videoDataSource = createDataSource(videoDeviceInfo.getLocator());
+ videoCaptureDevice = (CaptureDevice) videoDataSource;
+ }
+
+ // Create the av data source
+ if (audioDataSource != null && videoDataSource != null) {
+ DataSource[] allDS = new DataSource[] {
+ audioDataSource,
+ videoDataSource
+ };
+ try {
+ avDataSource = Manager.createMergingDataSource(allDS);
+ }
+ catch (IncompatibleSourceException exc) {
+ System.out.println(
+ "Failed to create a media data source!"
+ + "Media transmission won't be enabled!");
+ }
+ }
+ else {
+ if (audioDataSource != null) {
+ avDataSource = audioDataSource;
+ }
+ if (videoDataSource != null) {
+ avDataSource = videoDataSource;
+ }
+ }
+
+ // avDataSource may be null
+ }
+
+ protected void closeCaptureDevices()
+ {
+ try {
+ avDataSource.stop();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ protected DataSource getDataSource() {
+ return avDataSource;
+ }
+
+ protected DataSource createDataSource(MediaLocator locator)
+ {
+ try {
+ logger.info("Creating datasource for:"
+ + locator != null
+ ? locator.toExternalForm()
+ : "null");
+ return Manager.createDataSource(locator);
+ }
+ catch (NoDataSourceException ex) {
+ // The failure only concens us
+ logger.error("Could not create data source for " +
+ locator.toExternalForm());
+ return null;
+ }
+ catch (IOException ex) {
+ // The failure only concens us
+ logger.error("Could not create data source for " +
+ locator.toExternalForm());
+ return null;
+ }
+ }
+
+ protected void startCapture(CaptureDevice captureDevice)
+ {
+
+ }
+
+ protected void stopCapture(CaptureDevice captureDevice)
+ {
+
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/MediaDispatcher.java b/src/net/java/sip/communicator/impl/media/MediaDispatcher.java
new file mode 100644
index 0000000..1bf5489
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/MediaDispatcher.java
@@ -0,0 +1,119 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.media;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.configuration.ChangeEventDispatcher;
+import net.java.sip.communicator.service.configuration.event.VetoableChangeListener;
+import net.java.sip.communicator.service.media.event.*;
+import net.java.sip.communicator.service.media.*;
+
+/**
+ * This is a utility class that can be used by objects that support constrained
+ * properties. You can use an instance of this class as a member field
+ * of your bean and delegate various work to it.
+ *
+ * This class is serializable. When it is serialized it will save
+ * (and restore) any listeners that are themselves serializable. Any
+ * non-serializable listeners will be skipped during serialization.
+ *
+ * @author Martin Andre
+ */
+public class MediaDispatcher
+{
+
+ /**
+ * All media listeners registered so far.
+ */
+ private Vector mediaListeners;
+
+
+ public MediaDispatcher() {}
+
+ /**
+ * Add a mediaListener to the listener list.
+ *
+ * @param listener The MediaListener to be added
+ */
+ protected synchronized void addMediaListener(MediaListener listener)
+ {
+ if (mediaListeners == null)
+ {
+ mediaListeners = new Vector();
+ }
+
+ mediaListeners.addElement(listener);
+ }
+
+ /**
+ * Remove a MediaListener from the listener list.
+ *
+ * @param listener The MediaListener to be removed
+ */
+ protected synchronized void removeMediaListener(MediaListener listener)
+ {
+ if (mediaListeners == null)
+ {
+ return;
+ }
+ mediaListeners.removeElement(listener);
+ }
+
+ /**
+ * Alert all media listeners that we're receiving a media stream.
+ * @param mediaEvent the source of the event
+ */
+ protected void fireReceivedMediaStream(MediaEvent mediaEvent)
+ {
+ Vector targets = null;
+ synchronized (this)
+ {
+ if (mediaListeners != null)
+ {
+ targets = (Vector) mediaListeners.clone();
+ }
+ }
+
+ if (targets != null)
+ {
+ for (int i = 0; i < targets.size(); i++)
+ {
+ MediaListener target =
+ (MediaListener) targets.elementAt(i);
+
+ target.receivedMediaStream(mediaEvent);
+ }
+ }
+ }
+
+ /**
+ * Alert all media listeners that status has changed.
+ */
+ protected void fireMediaServiceStatusChanged()
+ {
+ Vector targets = null;
+ synchronized (this)
+ {
+ if (mediaListeners != null)
+ {
+ targets = (Vector) mediaListeners.clone();
+ }
+ }
+
+ if (targets != null)
+ {
+ for (int i = 0; i < targets.size(); i++)
+ {
+ MediaListener target =
+ (MediaListener) targets.elementAt(i);
+
+ target.mediaServiceStatusChanged();
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/MediaServiceImpl.java b/src/net/java/sip/communicator/impl/media/MediaServiceImpl.java
new file mode 100644
index 0000000..d4a8e51
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/MediaServiceImpl.java
@@ -0,0 +1,200 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.media;
+
+
+import javax.media.Player;
+import javax.sdp.SdpFactory;
+import javax.swing.JPanel;
+
+import com.sun.media.protocol.DataSource;
+
+import net.java.sip.communicator.impl.media.configuration.MediaConfiguration;
+import net.java.sip.communicator.service.configuration.ConfigurationService;
+import net.java.sip.communicator.service.media.MediaService;
+import net.java.sip.communicator.service.media.event.MediaEvent;
+import net.java.sip.communicator.service.media.event.MediaListener;
+import net.java.sip.communicator.service.protocol.CallParticipant;
+import net.java.sip.communicator.util.Logger;
+
+
+
+/**
+ * The service is meant to be a wrapper of media libraries such as JMF,
+ * (J)FFMPEG, JMFPAPI, and others. It takes care of all media play and capture
+ * as well as media transport (e.g. over RTP).
+ *
+ * Before being able to use this service calles would have to make sure that
+ * it is initialized (i.e. consult the isInitialized() method).
+ *
+ * @author Martin Andre
+ */
+public class MediaServiceImpl
+ implements MediaService
+{
+ private Logger logger = Logger.getLogger(MediaServiceImpl.class);
+
+ private SdpFactory sdpFactory;
+ private boolean isInitialized = false;
+
+ private Player player = null;
+ private JPanel videoPanel = null;
+
+ /**
+ * Our event dispatcher.
+ */
+ private MediaDispatcher mediaDispatcher = new MediaDispatcher();
+
+ /**
+ * Our configuration helper.
+ */
+ private MediaConfiguration mediaConfiguration = new MediaConfiguration();
+
+ /**
+ * Our media control helper.
+ */
+ private MediaControl mediaControl = new MediaControl(mediaConfiguration);
+
+ /**
+ * Default constructor
+ */
+ public MediaServiceImpl() {
+ }
+
+ /**
+ * Set the configuration service.
+ *
+ * @param configurationService
+ */
+ public void setConfigurationService(ConfigurationService configurationService) {
+ mediaConfiguration.setConfigurationService(configurationService);
+ }
+
+ /**
+ * Remove a configuration service.
+ *
+ * @param configurationService
+ */
+ public void unsetConfigurationService(ConfigurationService configurationService) {
+ mediaConfiguration.unsetConfigurationService(configurationService);
+ }
+
+ /**
+ * The method is meant for use by protocol service implementations when
+ * willing to send an invitation to a remote callee. It is at that point
+ * that the media service would open a port where it would be waiting for
+ * data coming from the specified call participant. Subsequent sdpoffers
+ * requested for the call that the original call participant belonged to,
+ * would receive, the same IP/port couple as the first one in order to allow
+ * conferencing. The associated port will be released once the call has
+ * ended. See RFC3264 for details on Offer/Answer model with SDP.
+ *
+ * @param callParticipant the call participant meant to receive the offer
+ * @return a String containing an SDP offer.
+ */
+ public String generateSdpOffer(CallParticipant callParticipant)
+ {
+ try
+ {
+ logger.logEntry();
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ return null;
+ }
+
+ /**
+ * The method is meant for use by protocol service implementations when
+ * willing to respond to an invitation received from a remote caller. It is
+ * at that point that the media service would open a port where it would
+ * wait for data coming from the specified call participant. Subsequent sdp
+ * offers/answers requested for the call that the original call participant
+ * belonged to will receive the same IP/port couple as the first one in
+ * order to allow conferencing. The associated port will be released once
+ * the call has ended. See RFC3264 for details on Offer/Answer model with SDP.
+ *
+ * @param callParticipant the call participant meant to receive the offer
+ * @return a String containing an SDP offer.
+ */
+ public String generateSdpAnswer(CallParticipant callParticipant)
+ {
+ try
+ {
+ logger.logEntry();
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ return null;
+ }
+
+ /**
+ * Adds a listener that will be listening for incoming media and changes
+ * in the state of the media listener
+ * @param listener the listener to register
+ */
+ public void addMediaListener(MediaListener listener) {
+ mediaDispatcher.addMediaListener(listener);
+ }
+
+ /**
+ * Removes a listener that was listening for incoming media and changes
+ * in the state of the media listener
+ * @param listener the listener to remove
+ */
+ public void removeMediaListener(MediaListener listener) {
+ mediaDispatcher.removeMediaListener(listener);
+ }
+
+ /**
+ * Initializes the service implementation, and puts it in a state where it
+ * could interoperate with other services.
+ */
+ public void initialize() {
+ openCaptureDevices();
+ //createPlayer();
+
+ videoPanel = new JPanel();
+
+ // Now alert mediaListeners
+ MediaEvent mediaEvent = new MediaEvent(videoPanel);
+ mediaDispatcher.fireReceivedMediaStream(mediaEvent);
+
+ isInitialized = true;
+ }
+
+ /**
+ * Returns true if the media service implementation is initialized and ready
+ * for use by other services, and false otherwise.
+ */
+ public boolean isInitialized() {
+ return isInitialized;
+ }
+
+ /**
+ * Open capture devices specified by configuration service.
+ */
+ private void openCaptureDevices()
+ {
+ mediaControl.openCaptureDevices();
+// javax.media.protocol.DataSource dataSource = mediaControl.getDataSource();
+// dataSource.disconnect();
+ }
+
+ /**
+ * Makes the service implementation close all release any devices or other
+ * resources that it might have allocated and prepare for shutdown/garbage
+ * collection.
+ */
+ public void shutdown() {
+ isInitialized = false;
+ return;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/configuration/ConfigurationListener.java b/src/net/java/sip/communicator/impl/media/configuration/ConfigurationListener.java
new file mode 100644
index 0000000..ca209bb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/ConfigurationListener.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import net.java.sip.communicator.service.configuration.event.PropertyChangeEvent;
+import net.java.sip.communicator.service.configuration.event.PropertyChangeListener;
+import net.java.sip.communicator.util.*;
+
+
+/**
+ *
+ * @author Martin Andre
+ */
+public class ConfigurationListener
+ implements PropertyChangeListener
+{
+ private Logger logger = Logger.getLogger(ConfigurationListener.class);
+
+ public void propertyChange(PropertyChangeEvent evt) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/media/configuration/DirectSoundAuto.java b/src/net/java/sip/communicator/impl/media/configuration/DirectSoundAuto.java
new file mode 100644
index 0000000..c5f9624
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/DirectSoundAuto.java
@@ -0,0 +1,112 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)DirectSoundAuto.java 1.3 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import javax.media.*;
+import javax.media.protocol.*;
+import javax.media.format.AudioFormat;
+
+import net.java.sip.communicator.util.Logger;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import com.sun.media.protocol.dsound.DirectSoundStream;
+
+public class DirectSoundAuto {
+
+ private static final Logger logger = Logger.getLogger(DirectSoundAuto.class);
+
+ private static final String detectClass = "com.sun.media.protocol.dsound.DSound";
+ CaptureDeviceInfo[] devices = null;
+
+ public static void main(String[] args) {
+ new DirectSoundAuto();
+ System.exit(0);
+ }
+
+ private boolean supports(AudioFormat af) {
+ try {
+ com.sun.media.protocol.dsound.DSound ds;
+ ds = new com.sun.media.protocol.dsound.DSound(af, 1024);
+ ds.open();
+ ds.close();
+ } catch (Exception e) {
+ logger.error(e);
+ return false;
+ }
+ return true;
+ }
+
+ public DirectSoundAuto() {
+ boolean supported = false;
+ // instance JavaSoundDetector to check is javasound's capture is availabe
+ try {
+ Class cls = Class.forName(detectClass);
+ supported = true;
+ } catch (Throwable t) {
+ supported = false;
+ // t.printStackTrace();
+ }
+
+ logger.info("DirectSound Capture Supported = " + supported);
+
+ if (supported) {
+ // It's there, start to register JavaSound with CaptureDeviceManager
+ Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
+
+ // remove the old direct sound capturers
+ String name;
+ Enumeration enumeration = devices.elements();
+ while (enumeration.hasMoreElements()) {
+ CaptureDeviceInfo cdi = (CaptureDeviceInfo) enumeration.nextElement();
+ name = cdi.getName();
+ if (name.startsWith(com.sun.media.protocol.dsound.DataSource.NAME))
+ CaptureDeviceManager.removeDevice(cdi);
+ }
+ int LE = AudioFormat.LITTLE_ENDIAN;
+ int SI = AudioFormat.SIGNED;
+ int US = AudioFormat.UNSIGNED;
+ int UN = AudioFormat.NOT_SPECIFIED;
+ float [] Rates = new float[] {
+ 48000, 44100, 32000, 22050, 16000, 11025, 8000
+ };
+ Vector formats = new Vector(4);
+ for (int rateIndex = 0; rateIndex < Rates.length; rateIndex++) {
+ float rate = Rates[rateIndex];
+ AudioFormat af;
+ af = new AudioFormat(AudioFormat.LINEAR, rate, 16, 2, LE, SI);
+ if (supports(af)) formats.addElement(af);
+ af = new AudioFormat(AudioFormat.LINEAR, rate, 16, 1, LE, SI);
+ if (supports(af)) formats.addElement(af);
+ af = new AudioFormat(AudioFormat.LINEAR, rate, 8, 2, UN, US);
+ if (supports(af)) formats.addElement(af);
+ af = new AudioFormat(AudioFormat.LINEAR, rate, 8, 1, UN, US);
+ if (supports(af)) formats.addElement(af);
+ }
+
+ AudioFormat [] formatArray = new AudioFormat[formats.size()];
+ for (int fa = 0; fa < formatArray.length; fa++)
+ formatArray[fa] = (AudioFormat) formats.elementAt(fa);
+
+ CaptureDeviceInfo cdi = new CaptureDeviceInfo(
+ com.sun.media.protocol.dsound.DataSource.NAME,
+ new MediaLocator("dsound://"),
+ formatArray);
+ CaptureDeviceManager.addDevice(cdi);
+ try {
+ CaptureDeviceManager.commit();
+ logger.info("DirectSoundAuto: Committed ok");
+ } catch (java.io.IOException ioe) {
+ logger.error("DirectSoundAuto: error committing cdm");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/media/configuration/JMFInit.java b/src/net/java/sip/communicator/impl/media/configuration/JMFInit.java
new file mode 100644
index 0000000..09186e5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/JMFInit.java
@@ -0,0 +1,395 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)JMFInit.java 1.14 03/04/30
+ * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Vector;
+
+import javax.media.Format;
+import javax.media.PlugInManager;
+import javax.media.Renderer;
+import javax.media.format.AudioFormat;
+
+import net.java.sip.communicator.util.Logger;
+
+import com.sun.media.ExclusiveUse;
+
+
+public class JMFInit
+ implements Runnable {
+
+ private static final Logger logger = Logger.getLogger(JMFInit.class);
+
+ public JMFInit() {
+
+// try {
+// Registry.commit();
+// }
+// catch (Exception e) {
+// logger.error("Failed to commit to JMFRegistry!", e );
+// }
+
+
+ Thread detectThread = new Thread(this);
+ detectThread.run();
+
+/*
+ int slept = 0;
+ while (!done && slept < 60 * 1000 * 2) {
+ try {
+ Thread.currentThread().sleep(500);
+ }
+ catch (InterruptedException ie) {
+ }
+ slept += 500;
+ }
+
+ if (!done) {
+ console.error("Detection is taking too long! Aborting!");
+ message("Detection is taking too long! Aborting!");
+ }
+
+ try {
+ Thread.currentThread().sleep(2000);
+ }
+ catch (InterruptedException ie) {
+ }
+*/
+ }
+
+ /**
+ * Detect all capture devices
+ */
+ public void run() {
+ detectDirectAudio();
+ detectS8DirectAudio();
+ detectCaptureDevices();
+ }
+
+ private void detectCaptureDevices() {
+ // check if JavaSound capture is available
+ logger.info("Looking for Audio capturer");
+ Class dsauto = null;
+ try {
+ dsauto = Class.forName(
+ "net.java.sip.communicator.impl.media.configuration.DirectSoundAuto");
+ dsauto.newInstance();
+ logger.info("Finished detecting DirectSound capturer");
+ }
+ catch (ThreadDeath td) {
+ throw td;
+ }
+ catch (Throwable t) {
+ logger.warn("DirectSound capturer detection failed!", t);
+ }
+
+ Class jsauto = null;
+ try {
+ jsauto = Class.forName(
+ "net.java.sip.communicator.impl.media.configuration.JavaSoundAuto");
+ jsauto.newInstance();
+ logger.info("Finished detecting JavaSound capturer");
+ }
+ catch (ThreadDeath td) {
+ throw td;
+ }
+ catch (Throwable t) {
+ logger.warn("JavaSound capturer detection failed!", t);
+ }
+
+ // Check if VFWAuto or SunVideoAuto is available
+ logger.info("Looking for video capture devices");
+ Class auto = null;
+ Class autoPlus = null;
+// try {
+// auto = Class.forName(
+// "net.java.sip.communicator.impl.media.configuration.VFWAuto");
+// }
+// catch (Exception e) {
+// logger.warn("VFWAuto capturer detection failed!", e);
+// }
+// if (auto == null) {
+// try {
+// auto = Class.forName(
+// "net.java.sip.communicator.impl.media.configuration.SunVideoAuto");
+// }
+// catch (Exception ee) {
+// logger.warn("SunVideoAuto capturer detection failed!", ee);
+// }
+// try {
+// autoPlus = Class.forName(
+// "net.java.sip.communicator.impl.media.configuration.SunVideoPlusAuto");
+// }
+// catch (Exception ee) {
+// logger.warn("SunVideoPlusAuto capturer detection failed!", ee);
+// }
+// }
+ if (auto == null) {
+ try {
+ auto = Class.forName(
+ "net.java.sip.communicator.impl.media.configuration.V4LAuto");
+ }
+ catch (Exception ee) {
+ logger.warn("V4lAuto capturer detection failed!", ee);
+ }
+ }
+ try {
+ Object instance = auto.newInstance();
+ if (autoPlus != null) {
+ Object instancePlus = autoPlus.newInstance();
+ }
+ logger.info("Finished detecting video capture devices");
+ }
+ catch (ThreadDeath td) {
+ throw td;
+ }
+ catch (Throwable t) {
+ logger.error("Capture device detection failed!", t);
+ }
+ }
+
+ private void detectDirectAudio() {
+ Class cls;
+ int plType = PlugInManager.RENDERER;
+ String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
+ try {
+ // Check if this is the Windows Performance Pack - hack
+ cls = Class.forName(
+ "net.java.sip.communicator.impl.media.configuration.VFWAuto");
+ // Check if DS capture is supported, otherwise fail DS renderer
+ // since NT doesn't have capture
+ cls = Class.forName("com.sun.media.protocol.dsound.DSound");
+ // Find the renderer class and instantiate it.
+ cls = Class.forName(dar);
+
+ Renderer rend = (Renderer) cls.newInstance();
+ try {
+ // Set the format and open the device
+ AudioFormat af = new AudioFormat(AudioFormat.LINEAR,
+ 44100, 16, 2);
+ rend.setInputFormat(af);
+ rend.open();
+ Format[] inputFormats = rend.getSupportedInputFormats();
+ // Register the device
+ PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
+ plType);
+ // Move it to the top of the list
+ Vector rendList =
+ PlugInManager.getPlugInList(null, null, plType);
+ int listSize = rendList.size();
+ if (rendList.elementAt(listSize - 1).equals(dar)) {
+ rendList.removeElementAt(listSize - 1);
+ rendList.insertElementAt(dar, 0);
+ PlugInManager.setPlugInList(rendList, plType);
+ PlugInManager.commit();
+ //System.err.println("registered");
+ }
+ rend.close();
+ }
+ catch (Throwable t) {
+ //System.err.println("Error " + t);
+ }
+ }
+ catch (Throwable tt) {
+ }
+ }
+
+ private void detectS8DirectAudio() {
+ Class cls;
+ int plType = PlugInManager.RENDERER;
+ String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
+ try {
+ // Check if this is the solaris Performance Pack - hack
+ cls = Class.forName(
+ "net.java.sip.communicator.impl.media.configuration.SunVideoAuto");
+
+ // Find the renderer class and instantiate it.
+ cls = Class.forName(dar);
+
+ Renderer rend = (Renderer) cls.newInstance();
+
+ if (rend instanceof ExclusiveUse &&
+ ! ( (ExclusiveUse) rend).isExclusive()) {
+ // sol8+, DAR supports mixing
+ Vector rendList = PlugInManager.getPlugInList(null, null,
+ plType);
+ int listSize = rendList.size();
+ boolean found = false;
+ String rname = null;
+
+ for (int i = 0; i < listSize; i++) {
+ rname = (String) (rendList.elementAt(i));
+ if (rname.equals(dar)) { // DAR is in the registry
+ found = true;
+ rendList.removeElementAt(i);
+ break;
+ }
+ }
+
+ if (found) {
+ rendList.insertElementAt(dar, 0);
+ PlugInManager.setPlugInList(rendList, plType);
+ PlugInManager.commit();
+ }
+ }
+ }
+ catch (Throwable tt) {
+ }
+ }
+
+ /**
+ * Runs JMFInit the first time the application is started so that capture
+ * devices are properly detected and initialized by JMF.
+ */
+ public static void setupJMF()
+ {
+ try
+ {
+ logger.logEntry();
+
+ // .jmf is the place where we store the jmf.properties file used
+ // by JMF. if the directory does not exist or it does not contain
+ // a jmf.properties file, or if the jmf.properties file has 0 length
+ // then this is the first time we're running and should detect capture
+ // devices
+ String homeDir = System.getProperty("user.home");
+ File jmfDir = new File(homeDir, ".jmf");
+ String classpath = System.getProperty("java.class.path");
+ classpath += System.getProperty("path.separator") +
+ jmfDir.getAbsolutePath();
+ System.setProperty("java.class.path", classpath);
+
+ if (!jmfDir.exists())
+ jmfDir.mkdir();
+
+ File jmfProperties = new File(jmfDir, "jmf.properties");
+
+ if (!jmfProperties.exists()) {
+ try {
+ jmfProperties.createNewFile();
+ }
+ catch (IOException ex) {
+ logger.error(
+ "Failed to create jmf.properties - " +
+ jmfProperties.getAbsolutePath());
+ }
+ }
+
+ //if we're running on linux checkout that libjmutil.so is where it
+ //should be and put it there.
+// runLinuxPreInstall();
+
+ if (jmfProperties.length() == 0) {
+ JMFInit init = new JMFInit();
+ }
+ }
+ finally
+ {
+ logger.logExit();
+ }
+
+ }
+
+
+// private static void runLinuxPreInstall()
+// {
+// try {
+// logger.logEntry();
+//
+// if (Utils.getProperty("os.name") == null
+// || !Utils.getProperty("os.name").equalsIgnoreCase("Linux"))
+// return;
+//
+// try {
+// System.loadLibrary("jmv4l");
+// console.debug("Successfully loaded libjmv4l.so");
+// }
+// catch (UnsatisfiedLinkError err) {
+// console.debug("Failed to load libjmv4l.so. Will try and copy libjmutil.so", err);
+//
+// String destinationPathStr = Utils.getProperty("java.home")
+// + File.separator + "lib"
+// + File.separator + "i386";
+// String libjmutilFileStr = "libjmutil.so";
+//
+// try {
+// InputStream libIS =
+// MediaManager.class.getClassLoader().
+// getResourceAsStream(libjmutilFileStr);
+// File outFile = new File(destinationPathStr
+// +File.separator + libjmutilFileStr);
+//
+// //Check if file is already there - Ben Asselstine
+// if (outFile.exists()) {
+// //if we're here then libjmutil is already where it should be
+// // but yet we failed to load libjmv4l.
+// //so notify log and bail out
+// console.error(
+// "An error occurred while trying to load JMF. This "
+// +"error is probably due to a JMF installation problem. "
+// +"Please copy libjmutil.so to a location contained by "
+// + "$LD_LIBRARY_PATH and try again!",
+// err);
+// return;
+//
+// }
+//
+// outFile.createNewFile();
+//
+// console.debug("jmutil");
+//
+// FileOutputStream fileOS = new FileOutputStream(outFile);
+// int available = libIS.available();
+// byte[] bytes = new byte[libIS.available()];
+// int read = 0;
+// int i = 0;
+// for (i = 0; i<available ; i++)
+// {
+// bytes[i] = (byte)libIS.read();
+// }
+//
+// console.debug("Read " + i + " bytes out of " + available );
+//
+// fileOS.write(bytes, 0, bytes.length);
+// console.debug("Wrote " + available + " bytes.");
+// bytes = null;
+// libIS.close();
+// fileOS.close();
+// }
+// catch (IOException exc) {
+// if( exc.getMessage() != null
+// && exc.getMessage().toLowerCase().indexOf("permission denied") != -1)
+// console.showError("Permission denied!",
+// "Because of insufficient permissions SIP Communicator has failed "
+// + "to copy a required library to\n\n\t"
+// + destinationPathStr + "!\n\nPlease run the application as root or "
+// + "manually copy the " +libjmutilFileStr
+// + " file to the above location!\n");
+// exc.printStackTrace();
+// }
+// }
+// /** @todo check whether we have a permissions problem and alert the
+// * user that they should be running as root */
+// catch(Throwable t)
+// {
+// console.debug("Error while loading");
+// }
+// }
+// finally {
+// console.logExit();
+// }
+// }
+
+ public static void start() {
+ setupJMF();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/configuration/JavaSoundAuto.java b/src/net/java/sip/communicator/impl/media/configuration/JavaSoundAuto.java
new file mode 100644
index 0000000..3a72e58
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/JavaSoundAuto.java
@@ -0,0 +1,78 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)JavaSoundAuto.java 1.2 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.media.CaptureDeviceInfo;
+import javax.media.CaptureDeviceManager;
+
+import net.java.sip.communicator.util.Logger;
+
+public class JavaSoundAuto {
+
+ private static final Logger logger = Logger.getLogger(JavaSoundAuto.class);
+
+ private static final String detectClass =
+ "net.java.sip.communicator.impl.media.configuration.JavaSoundDetector";
+ CaptureDeviceInfo[] devices = null;
+
+ public static void main(String[] args) {
+ new JavaSoundAuto();
+ System.exit(0);
+ }
+
+ public JavaSoundAuto() {
+ boolean supported = false;
+ // instance JavaSoundDetector to check is javasound's capture is availabe
+ try {
+ Class cls = Class.forName(detectClass);
+ JavaSoundDetector detect = (JavaSoundDetector)cls.newInstance();
+ supported = detect.isSupported();
+ } catch (Throwable t) {
+ supported = false;
+ t.printStackTrace();
+ }
+
+ logger.info("JavaSound Capture Supported = " + supported);
+
+ if (supported) {
+ // It's there, start to register JavaSound with CaptureDeviceManager
+ Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
+
+ // remove the old javasound capturers
+ String name;
+ Enumeration enumeration = devices.elements();
+ while (enumeration.hasMoreElements()) {
+ CaptureDeviceInfo cdi = (CaptureDeviceInfo) enumeration.nextElement();
+ name = cdi.getName();
+ if (name.startsWith("JavaSound"))
+ CaptureDeviceManager.removeDevice(cdi);
+ }
+
+ // collect javasound capture device info from JavaSoundSourceStream
+ // and register them with CaptureDeviceManager
+ CaptureDeviceInfo[] cdi = com.sun.media.protocol.javasound.JavaSoundSourceStream.listCaptureDeviceInfo();
+ if ( cdi != null ){
+ for (int i = 0; i < cdi.length; i++)
+ CaptureDeviceManager.addDevice(cdi[i]);
+ try {
+ CaptureDeviceManager.commit();
+ logger.info("JavaSoundAuto: Committed ok");
+ } catch (java.io.IOException ioe) {
+ logger.error("JavaSoundAuto: error committing cdm");
+ }
+ }
+
+ }
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/media/configuration/JavaSoundDetector.java b/src/net/java/sip/communicator/impl/media/configuration/JavaSoundDetector.java
new file mode 100644
index 0000000..a3ad124
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/JavaSoundDetector.java
@@ -0,0 +1,37 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)JavaSoundDetector.java 1.2 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.TargetDataLine;
+
+
+public class JavaSoundDetector {
+
+ boolean supported = false;
+
+ public JavaSoundDetector() {
+ try {
+ DataLine.Info info = new DataLine.Info(TargetDataLine.class,
+ null,
+ AudioSystem.NOT_SPECIFIED);
+ supported = AudioSystem.isLineSupported(info);
+ } catch (Exception ex) {
+ supported = false;
+ }
+ }
+
+ public boolean isSupported() {
+ return supported;
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/media/configuration/MediaConfiguration.java b/src/net/java/sip/communicator/impl/media/configuration/MediaConfiguration.java
new file mode 100644
index 0000000..a919526
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/MediaConfiguration.java
@@ -0,0 +1,189 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import java.util.*;
+
+import javax.media.CaptureDeviceInfo;
+import javax.media.CaptureDeviceManager;
+import javax.media.format.AudioFormat;
+import javax.media.format.VideoFormat;
+import javax.media.protocol.CaptureDevice;
+import javax.media.protocol.DataSource;
+
+import net.java.sip.communicator.service.configuration.ConfigurationService;
+import net.java.sip.communicator.util.*;
+
+
+
+/**
+ * This class aims to provide a simple configuration interface for JMF.
+ * It retrieves stored configuration when started or listens to
+ * ConfigurationEvent for property changes and configures the JMF accordingly.
+ *
+ * @author Martin Andre
+ */
+public class MediaConfiguration
+{
+ private Logger logger = Logger.getLogger(MediaConfiguration.class);
+
+ private Object syncRoot_Config = new Object();
+
+ /**
+ * The configuration service to use when retrieving conf property values
+ */
+ private ConfigurationService configurationService = null;
+
+ /**
+ * Our configuration listener.
+ */
+ private ConfigurationListener configurationListener =
+ new ConfigurationListener();
+
+ /**
+ * Audio and Video transmission
+ */
+ private boolean audioTransmission = true;
+ private boolean videoTransmission = true;
+ private boolean audioReception = true;
+ private boolean videoReception = true;
+
+ /**
+ * Capture devices
+ */
+ private CaptureDeviceInfo audioCaptureDevice = null;
+ private CaptureDeviceInfo videoCaptureDevice = null;
+// private DataSource avDataSource = null;
+
+ /**
+ * Default constructor.
+ */
+ public MediaConfiguration() {
+ JMFInit.start();
+ detectConfiguredCaptureDevices();
+ }
+
+ /**
+ * Set the configuration service.
+ *
+ * @param configurationService
+ */
+ public void setConfigurationService(ConfigurationService configurationService) {
+ synchronized(this.syncRoot_Config) {
+ this.configurationService = configurationService;
+ logger.debug("New configuration service registered.");
+ }
+ // TODO add a list of proporties to listen to
+ this.configurationService.addPropertyChangeListener(configurationListener);
+ }
+
+ /**
+ * Remove a configuration service.
+ *
+ * @param configurationService
+ */
+ public void unsetConfigurationService(ConfigurationService configurationService) {
+ synchronized(this.syncRoot_Config) {
+ if (this.configurationService == configurationService) {
+ this.configurationService = null;
+ logger.debug("Configuration service unregistered.");
+ }
+ }
+ }
+
+ /**
+ * Detects capture devices configured through JMF and disable audio
+ * and/or video transmission if none were found.
+ * Stores found devices in audioCaptureDevice and videoCaptureDevice.
+ */
+ private void detectConfiguredCaptureDevices()
+ {
+ logger.info("Scanning for configured Audio Devices.");
+ Vector audioCaptureDevices = CaptureDeviceManager.getDeviceList(new
+ AudioFormat(AudioFormat.LINEAR, 44100, 16, 1));
+ if (audioCaptureDevices.size() < 1) {
+ logger.error("No Audio Device was found.");
+ audioCaptureDevice = null;
+ setAudioTransmission(false);
+ }
+ else {
+ audioCaptureDevice = (CaptureDeviceInfo) audioCaptureDevices.get(0);
+ logger.info("Found " + audioCaptureDevice.getName() +" as an audio capture device.");
+ }
+
+ logger.info("Scanning for configured Video Devices.");
+ Vector videoCaptureDevices = CaptureDeviceManager.getDeviceList(new
+ VideoFormat(VideoFormat.RGB));
+ if (videoCaptureDevices.size() > 0) {
+ videoCaptureDevice = (CaptureDeviceInfo) videoCaptureDevices.get(0);
+ logger.info("Found " + videoCaptureDevice.getName() + " as an RGB Video Device.");
+ }
+ // no RGB camera found. And what about YUV ?
+ else
+ {
+ videoCaptureDevices = CaptureDeviceManager.getDeviceList(new
+ VideoFormat(VideoFormat.YUV));
+ if (videoCaptureDevices.size() > 0) {
+ videoCaptureDevice = (CaptureDeviceInfo) videoCaptureDevices.get(0);
+ logger.info("Found " + videoCaptureDevice.getName() + " as an YUV Video Device.");
+ }
+ else {
+ logger.error("No Video Device was found.");
+ videoCaptureDevice = null;
+ setVideoTransmission(false);
+ }
+ }
+ }
+
+ public CaptureDeviceInfo getAudioCaptureDevice() {
+ return audioCaptureDevice;
+ }
+
+ public CaptureDeviceInfo getVideoCaptureDevice() {
+ return videoCaptureDevice;
+ }
+
+ /**
+ * Enable or disable Audio stream transmission.
+ * @param enable whereas Audio stream transmission must be enabled or disabled
+ */
+ protected void setAudioTransmission(boolean enable) {
+ logger.info(enable? "Enabling":"Disabling"
+ + " Audio transmission.");
+ this.audioTransmission = enable;
+ }
+
+ /**
+ * Enable or disable Video stream transmission.
+ * @param enable whereas Video stream transmission must be enabled or disabled
+ */
+ protected void setVideoTransmission(boolean enable) {
+ logger.info(enable? "Enabling":"Disabling"
+ + " Video transmission.");
+ this.videoTransmission = enable;
+ }
+
+ /**
+ * Enable or disable Audio stream reception.
+ * @param enable whereas Audio stream reception must be enabled or disabled
+ */
+ protected void setAudioReception(boolean enable) {
+ logger.info(enable? "Enabling":"Disabling"
+ + " Audio reception.");
+ this.audioReception = enable;
+ }
+
+ /**
+ * Enable or disable Video stream reception.
+ * @param enable whereas Video stream reception must be enabled or disabled
+ */
+ protected void setVideoReception(boolean enable) {
+ logger.info(enable? "Enabling":"Disabling"
+ + " Video reception.");
+ this.videoReception = enable;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/configuration/SunVideoAuto.java b/src/net/java/sip/communicator/impl/media/configuration/SunVideoAuto.java
new file mode 100644
index 0000000..8507b4a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/SunVideoAuto.java
@@ -0,0 +1,183 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)SunVideoAuto.java 1.8 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import javax.media.*;
+import javax.media.Format;
+import javax.media.format.VideoFormat;
+import javax.media.format.RGBFormat;
+
+import net.java.sip.communicator.util.Logger;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import com.sun.media.protocol.sunvideo.*;
+
+public class SunVideoAuto {
+
+ private static final Logger logger = Logger.getLogger(SunVideoAuto.class);
+
+ private static String DEVICE_PREFIX = "/dev/rtvc";
+ private static String PROTOCOL = "sunvideo";
+ private static String LOCATOR_PREFIX = PROTOCOL + "://";
+ CaptureDeviceInfo [] devices = null;
+ int currentID = -1;
+
+ XILCapture xilCap;
+
+ Vector formats = null;
+
+ int [] ports = { 1, 2, 0 }; // most likely ports for a device
+
+ int [] scales = { 2, 4, 1 }; // supported scales / sizes
+
+
+ public SunVideoAuto() {
+ Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
+ Enumeration enumeration = devices.elements();
+ while (enumeration.hasMoreElements()) {
+ CaptureDeviceInfo cdi = (CaptureDeviceInfo) enumeration.nextElement();
+ String devName = cdi.getLocator().getProtocol();
+ if (devName.equals(PROTOCOL))
+ CaptureDeviceManager.removeDevice(cdi);
+ }
+
+ int nDevices = 0;
+ for (int i = 0; i < 7; i++) {
+ File fl = new File(DEVICE_PREFIX + i);
+ if (fl.exists()) {
+ doDevice(i);
+ nDevices++;
+ }
+ }
+ try {
+ CaptureDeviceManager.commit();
+ logger.info("SunVideoAuto: Committed ok");
+ } catch (java.io.IOException ioe) {
+ logger.error("SunVideoAuto: error committing cdm");
+ }
+ }
+
+ private void addFormat(Format fin) {
+ Enumeration enumeration = formats.elements();
+ while (enumeration.hasMoreElements()) {
+ Format f = (Format) enumeration.nextElement();
+ if (f.equals(fin))
+ return;
+ }
+
+ //System.err.println("New format = " + fin);
+ formats.addElement(fin);
+ }
+
+ private void doDevice(int index) {
+
+ xilCap = new XILCapture(null);
+ VideoFormat vf;
+ formats = new Vector();
+ boolean gotPort = false;
+
+ if (!xilCap.connect(index)) {
+ dummyDevice(index);
+ return;
+ }
+
+
+ for (int i = 0; i < ports.length; i++) {
+ if (xilCap.setPort(ports[i])) {
+ getJpegFormats(i);
+ getRGBFormats(i);
+ }
+ }
+ xilCap.disconnect();
+
+ if (formats.size() > 0)
+ addDevice(index);
+ else
+ dummyDevice(index);
+ }
+
+
+ private void getRGBFormats(int index) {
+ if (!xilCap.setCompress("RGB"))
+ return;
+ for (int i = 0; i < scales.length; i++) {
+ xilCap.setScale(scales[i]);
+ // To get the real values, start the device
+ if (xilCap.start()) {
+ Dimension size = new Dimension(xilCap.getWidth(),
+ xilCap.getHeight());
+ int stride = xilCap.getLineStride();
+ int maxbuf = stride * size.width;
+ addFormat(new RGBFormat(size, maxbuf, byte[].class,
+ 15f,
+ 24,
+ 3, 2, 1, 3, stride,
+ Format.FALSE,
+ Format.NOT_SPECIFIED));
+ }
+ xilCap.stop();
+ }
+ }
+
+ private void getJpegFormats(int index) {
+ if (!xilCap.setCompress("Jpeg"))
+ return;
+ for (int i = 0; i < scales.length; i++) {
+ xilCap.setScale(scales[i]);
+ // To get the real values, start the device
+ if (xilCap.start()) {
+ Dimension size = new Dimension(xilCap.getWidth(),
+ xilCap.getHeight());
+ // approximate the max for high quality
+ int maxbuf = 3 * size.width * size.height;
+ addFormat(new VideoFormat(VideoFormat.JPEG, size, maxbuf,
+ byte[].class, 15f));
+ }
+ xilCap.stop();
+ }
+ }
+
+ private void dummyDevice(int index) {
+ // Can't get to the device, use the barest formats
+ addFormat(new VideoFormat(VideoFormat.JPEG));
+ addFormat(new RGBFormat());
+ addDevice(index);
+ }
+
+
+ private void addDevice(int index) {
+
+ String name = "SunVideo device " + index;
+ String locator = LOCATOR_PREFIX + index;
+
+ Format [] farray = new Format[formats.size()];
+ Enumeration enumeration = formats.elements();
+
+ int i = 0;
+ while (enumeration.hasMoreElements()) {
+ Format f = (Format) enumeration.nextElement();
+ farray[i++] = f;
+ }
+
+ CaptureDeviceInfo cdi = new CaptureDeviceInfo(name,
+ new MediaLocator(locator), farray);
+ CaptureDeviceManager.addDevice(cdi);
+ }
+
+ public static void main(String [] args) {
+ SunVideoAuto a = new SunVideoAuto();
+ System.exit(0);
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/media/configuration/SunVideoPlusAuto.java b/src/net/java/sip/communicator/impl/media/configuration/SunVideoPlusAuto.java
new file mode 100644
index 0000000..f0faa5f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/SunVideoPlusAuto.java
@@ -0,0 +1,393 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)SunVideoPlusAuto.java 1.6 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.media.CaptureDeviceInfo;
+import javax.media.CaptureDeviceManager;
+import javax.media.Format;
+import javax.media.Manager;
+import javax.media.MediaLocator;
+import javax.media.format.RGBFormat;
+import javax.media.format.VideoFormat;
+import javax.media.format.YUVFormat;
+import javax.media.protocol.CaptureDevice;
+
+import com.sun.media.protocol.sunvideoplus.*;
+
+public class SunVideoPlusAuto {
+
+ private static String DEVICE_PREFIX = "/dev/o1k";
+ private static String PROTOCOL = "sunvideoplus";
+ private static String LOCATOR_PREFIX = PROTOCOL + "://";
+
+ private static boolean DO_PAL = false;
+
+ int currentID = -1;
+
+ public SunVideoPlusAuto() {
+ /*
+ * First remove any old entries
+ */
+ Vector devices = (Vector) CaptureDeviceManager.
+ getDeviceList(null).clone();
+ Enumeration enumeration = devices.elements();
+ while (enumeration.hasMoreElements()) {
+ CaptureDeviceInfo cdi = (CaptureDeviceInfo) enumeration.nextElement();
+ String devName = cdi.getLocator().getProtocol();
+ if (devName.equals(PROTOCOL))
+ CaptureDeviceManager.removeDevice(cdi);
+ }
+
+ int nDevices = 0;
+ for (int i = 0; i < 10; i++) {
+ File fl = new File(DEVICE_PREFIX + i);
+ if (fl.exists()) {
+ if (DO_PAL) {
+ generalDevice(i, "PAL");
+ // If generating PAL, do both
+ // Garbage collect to release the PAL datasource
+ // otherwise it sometimes hangs before completing NTSC
+ System.gc();
+ generalDevice(i, "NTSC");
+ } else {
+ generalDevice(i, null);
+ }
+ // No longer generate specific configurations,
+ // let capture preview handle selection.
+ // doDevice(i);
+ nDevices++;
+ }
+ }
+
+ try {
+ CaptureDeviceManager.commit();
+ System.err.println("SunVideoPlusAuto: Committed ok");
+ } catch (java.io.IOException ioe) {
+ System.err.println("SunVideoPlusAuto: error committing cdm");
+ }
+ }
+
+ protected void generalDevice(int id, String signal) {
+ // Add the general device
+ javax.media.protocol.DataSource dsource = null;
+ String url = LOCATOR_PREFIX + id;
+ if (signal != null)
+ url += "////" + signal.toLowerCase();
+ try {
+ dsource = Manager.createDataSource(new MediaLocator(url));
+ } catch (Exception ex) {
+ }
+ if (dsource != null && dsource instanceof
+ com.sun.media.protocol.sunvideoplus.DataSource) {
+ CaptureDeviceInfo cdi = ((CaptureDevice)dsource).
+ getCaptureDeviceInfo();
+ if (cdi != null) {
+ String name = cdi.getName();
+ if (signal == null) {
+ CaptureDeviceManager.addDevice(cdi);
+ } else {
+ name = cdi.getName() + " (" + signal + ")";
+ CaptureDeviceManager.addDevice(new CaptureDeviceInfo(name,
+ cdi.getLocator(), cdi.getFormats()));
+ }
+ System.err.println("CaptureDeviceInfo = "
+ + name + " "
+ + cdi.getLocator());
+ }
+ dsource.disconnect();
+ }
+ }
+
+ protected void doDevice(int id) {
+ currentID = id;
+ FormatSetup fd = new FormatSetup(currentID);
+ Vector cdiv = fd.getDeviceInfo();
+ if (cdiv != null && cdiv.size() > 0) {
+ for (int i = 0; i < cdiv.size(); i++) {
+ CaptureDeviceInfo cdi =
+ (CaptureDeviceInfo) cdiv.elementAt(i);
+ // At the moment, the name and locator are identical
+ System.err.println("CaptureDeviceInfo = "
+ + cdi.getName());
+// System.err.println("CaptureDeviceInfo = "
+// + cdi.getName() + " "
+// + cdi.getLocator());
+ }
+ }
+ }
+
+ class FormatSetup {
+
+ int id;
+
+ boolean fullVideo = false;
+ boolean anyVideo = true;
+
+ String sAnalog, sPort, sVideoFormat, sSize;
+
+ Hashtable videoFormats = new Hashtable();
+
+ OPICapture opiVidCap = null;
+
+ public FormatSetup(int id) {
+ this.id = id;
+ opiVidCap = new OPICapture(null);
+ if (!opiVidCap.connect(id)) {
+ throw new Error("Unable to connect to device");
+ }
+
+ }
+
+ private void addVideoFormat(Format fin) {
+ String sVideo = sPort + "/" + sVideoFormat + "/"
+ + sSize + "/"
+ + sAnalog;
+ System.err.println("New format " + sVideo + " = " + fin);
+ videoFormats.put(sVideo, fin);
+ }
+
+ public void mydispose() {
+ opiVidCap.disconnect();
+ System.err.println("Disconnected driver");
+ }
+
+ public void doFormat() {
+ if (anyVideo) {
+ doVideoFormats();
+ }
+ }
+
+ public void doVideoFormats() {
+ if (!anyVideo) {
+ // add a dummy format entry
+ videoFormats.put("off", new VideoFormat(VideoFormat.RGB));
+ }
+
+ sAnalog = "ntsc";
+ if (DO_PAL)
+ sAnalog = "pal";
+ if (!opiVidCap.setSignal(sAnalog)) {
+ System.err.println("Video analog signal not recognized");
+ return;
+ }
+ int port = 1;
+ if (!opiVidCap.setPort(port)) {
+ System.err.println("Video source not recognized on port");
+ return;
+ }
+ sPort = "" + port;
+ opiVidCap.setScale(2);
+ sSize = "cif";
+ getVideoFormats();
+ }
+
+ private void getVideoFormats() {
+ sVideoFormat = "h261";
+ getH261Format();
+ sVideoFormat = "h263";
+ getH263Format();
+ sVideoFormat = "jpeg";
+ getJpegFormat();
+ sVideoFormat = "rgb";
+ getRGBFormat();
+ sVideoFormat = "yuv";
+ getYUVFormat();
+ }
+
+ private void getRGBFormat() {
+ if (!opiVidCap.setCompress("RGB"))
+ return;
+ /*
+ * If sizes are wanted, the only valid sizes are
+ * NTSC
+ * fcif (640 x 480)
+ * cif (320 x 240)
+ * qcif (160 x 120)
+ * PAL
+ * fcif (768 x 576)
+ * cif (384 x 288)
+ * qcif (192 x 144)
+ */
+ Dimension size = new Dimension(opiVidCap.getWidth(),
+ opiVidCap.getHeight());
+ addVideoFormat(new RGBFormat(size, Format.NOT_SPECIFIED,
+ Format.byteArray,
+ Format.NOT_SPECIFIED,
+ 16,
+ 0xF800, 0x7E0, 0x1F, 2,
+ Format.NOT_SPECIFIED,
+ Format.FALSE,
+ Format.NOT_SPECIFIED));
+ }
+
+ private void getYUVFormat() {
+ if (!opiVidCap.setCompress("YUV"))
+ return;
+ /*
+ * If sizes are wanted, the only valid sizes are
+ * NTSC
+ * fcif (640 x 480)
+ * cif (320 x 240)
+ * qcif (160 x 120)
+ * PAL
+ * fcif (768 x 576)
+ * cif (384 x 288)
+ * qcif (192 x 144)
+ *
+ * The capture stream is actually interleaved YVYU format.
+ * This is defined in the offset values below.
+ */
+ Dimension size = new Dimension(opiVidCap.getWidth(),
+ opiVidCap.getHeight());
+ addVideoFormat(new YUVFormat(size, Format.NOT_SPECIFIED,
+ Format.byteArray,
+ Format.NOT_SPECIFIED,
+ YUVFormat.YUV_YUYV,
+ Format.NOT_SPECIFIED,
+ Format.NOT_SPECIFIED,
+ 0, 3, 1));
+ }
+
+ private void getJpegFormat() {
+ if (!opiVidCap.setCompress("Jpeg"))
+ return;
+ /*
+ * If sizes are wanted, the only valid sizes are
+ * NTSC
+ * cif (320 x 240)
+ * qcif (160 x 120)
+ * PAL
+ * cif (384 x 288)
+ * qcif (192 x 144)
+ */
+ Dimension size = new Dimension(opiVidCap.getWidth(),
+ opiVidCap.getHeight());
+ addVideoFormat(new VideoFormat(VideoFormat.JPEG, size,
+ Format.NOT_SPECIFIED,
+ Format.byteArray,
+ Format.NOT_SPECIFIED));
+ }
+
+ private void getH261Format() {
+ if (!opiVidCap.setCompress("H261"))
+ return;
+ /*
+ * If sizes are wanted, the only valid sizes are
+ * cif (352 x 288)
+ * qcif (176 x 144)
+ */
+ Dimension size = new Dimension(opiVidCap.getWidth(),
+ opiVidCap.getHeight());
+ addVideoFormat(new VideoFormat(VideoFormat.H261, size,
+ Format.NOT_SPECIFIED,
+ Format.byteArray,
+ Format.NOT_SPECIFIED));
+ }
+
+ private void getH263Format() {
+ if (!opiVidCap.setCompress("H263"))
+ return;
+ /*
+ * If sizes are wanted, the only valid sizes are
+ * cif (352 x 288)
+ * qcif (176 x 144)
+ */
+ Dimension size = new Dimension(opiVidCap.getWidth(),
+ opiVidCap.getHeight());
+ addVideoFormat(new VideoFormat(VideoFormat.H263, size,
+ Format.NOT_SPECIFIED,
+ Format.byteArray,
+ Format.NOT_SPECIFIED));
+ }
+
+
+ public void issueError(String err) {
+ System.err.println(err);
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ public Enumeration sortedFormats(Hashtable formats) {
+ Vector sorted = new Vector();
+ keyloop: for (Enumeration en = formats.keys();
+ en.hasMoreElements(); ) {
+ String key = (String) en.nextElement();
+ for (int i = 0; i < sorted.size(); i++) {
+ if (key.compareTo((String)sorted.elementAt(i)) < 0) {
+ sorted.insertElementAt(key, i);
+ continue keyloop;
+ }
+ }
+ sorted.addElement(key);
+ }
+ return sorted.elements();
+ }
+
+
+ public Vector getDeviceInfo() {
+ doFormat();
+ mydispose();
+
+ String locatorPrefix = LOCATOR_PREFIX + id;
+ Vector devices = new Vector();
+ if (anyVideo) {
+
+ for (Enumeration ve = sortedFormats(videoFormats);
+ ve.hasMoreElements(); ) {
+ String vKey = (String) ve.nextElement();
+ Format vForm = (VideoFormat)videoFormats.get(vKey);
+ Format[] farray = null;
+ farray = new Format[1];
+ farray[0] = vForm;
+ String name = locatorPrefix + "/" + vKey;
+ CaptureDeviceInfo cdi = new CaptureDeviceInfo(name,
+ new MediaLocator(name), farray);
+ CaptureDeviceManager.addDevice(cdi);
+ devices.addElement(cdi);
+ }
+ }
+ return devices;
+ }
+
+ }
+
+ public static void setPALSignal(boolean pal) {
+ DO_PAL = pal;
+ }
+
+ public static void main(String [] args) {
+ if (args.length > 0) {
+ if (args.length > 1) {
+ System.err.println(
+ "Usage: java SunVideoPlusAuto [ ntsc | pal ]");
+ System.exit(1);
+ }
+ if (args[0].equalsIgnoreCase("ntsc")) {
+ SunVideoPlusAuto.setPALSignal(false);
+ } else if (args[0].equalsIgnoreCase("pal")) {
+ SunVideoPlusAuto.setPALSignal(true);
+ } else {
+ System.err.println(
+ "Usage: java SunVideoPlusAuto [ ntsc | pal ]");
+ System.exit(1);
+ }
+ }
+ SunVideoPlusAuto m = new SunVideoPlusAuto();
+ System.exit(0);
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/media/configuration/V4LAuto.java b/src/net/java/sip/communicator/impl/media/configuration/V4LAuto.java
new file mode 100644
index 0000000..0bbe382
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/V4LAuto.java
@@ -0,0 +1,70 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)V4LAuto.java 1.2 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.media.CaptureDeviceInfo;
+import javax.media.CaptureDeviceManager;
+
+import net.java.sip.communicator.util.Logger;
+
+import com.sun.media.protocol.v4l.V4LDeviceQuery;
+
+public class V4LAuto {
+
+ private static final Logger logger = Logger.getLogger(V4LAuto.class);
+
+ public V4LAuto() {
+ Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
+ Enumeration enumeration = devices.elements();
+ while (enumeration.hasMoreElements()) {
+ CaptureDeviceInfo cdi = (CaptureDeviceInfo) enumeration.nextElement();
+ String name = cdi.getName();
+ if (name.startsWith("v4l:"))
+ CaptureDeviceManager.removeDevice(cdi);
+ }
+
+ autoDetect(0);
+// for (int i = 0; i < 10; i++) {
+// autoDetect(i);
+// }
+ }
+
+ protected CaptureDeviceInfo autoDetect(int cardNo) {
+ CaptureDeviceInfo cdi = null;
+ try {
+ cdi = new V4LDeviceQuery(cardNo);
+ if ( cdi != null && cdi.getFormats() != null &&
+ cdi.getFormats().length > 0) {
+ // Commit it to disk. Its a new device
+ if (CaptureDeviceManager.addDevice(cdi)) {
+ logger.info("Added device " + cdi);
+ CaptureDeviceManager.commit();
+ }
+
+ }
+ } catch (Throwable t) {
+ logger.error("Could not add device!", t);
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath)t;
+ }
+
+ return cdi;
+ }
+
+ public static void main(String [] args) {
+ V4LAuto a = new V4LAuto();
+ System.exit(0);
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/media/configuration/VFWAuto.java b/src/net/java/sip/communicator/impl/media/configuration/VFWAuto.java
new file mode 100644
index 0000000..4e4bce1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/configuration/VFWAuto.java
@@ -0,0 +1,52 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * File based on:
+ * @(#)VFWAuto.java 1.2 01/03/13
+ * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
+ */
+package net.java.sip.communicator.impl.media.configuration;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.media.CaptureDeviceInfo;
+import javax.media.CaptureDeviceManager;
+
+import com.sun.media.vfw.*;
+import com.sun.media.util.WindowUtil;
+
+public class VFWAuto {
+
+ public VFWAuto() {
+ Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
+ Enumeration enumeration = devices.elements();
+
+ while (enumeration.hasMoreElements()) {
+ CaptureDeviceInfo cdi = (CaptureDeviceInfo) enumeration.nextElement();
+ String name = cdi.getName();
+ if (name.startsWith("vfw:"))
+ CaptureDeviceManager.removeDevice(cdi);
+ }
+
+ int nDevices = 0;
+// for (int i = 0; i < 10; i++) {
+// String name = VFWCapture.capGetDriverDescriptionName(i);
+// if (name != null && name.length() > 1) {
+// System.err.println("Found device " + name);
+// System.err.println("Querying device. Please wait...");
+// com.sun.media.protocol.vfw.VFWSourceStream.autoDetect(i);
+// nDevices++;
+// }
+// }
+ }
+
+ public static void main(String [] args) {
+ VFWAuto a = new VFWAuto();
+ System.exit(0);
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/media/media.manifest.mf b/src/net/java/sip/communicator/impl/media/media.manifest.mf
new file mode 100644
index 0000000..947b202
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/media.manifest.mf
@@ -0,0 +1,23 @@
+Bundle-Activator: net.java.sip.communicator.impl.media.Activator
+Bundle-Name: Media Service Implementation
+Bundle-Description: A bundle that offers Media capture and presentation capabilities.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.ungoverned.gravity.servicebinder,
+ org.osgi.framework,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.configuration.event,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.util,
+ javax.media,
+ javax.media.format,
+ javax.media.protocol,
+ javax.sound.sampled,
+ javax.swing,
+ com.sun.media.protocol.javasound,
+ com.sun.media.protocol.v4l,
+Export-Package: net.java.sip.communicator.service.media,
+ net.java.sip.communicator.service.media.event,
+ net.java.sip.communicator.impl.media,
+ net.java.sip.communicator.impl.media.event,
+Metadata-Location: /net/java/sip/communicator/impl/media/media.metadata.xml
diff --git a/src/net/java/sip/communicator/impl/media/media.metadata.xml b/src/net/java/sip/communicator/impl/media/media.metadata.xml
new file mode 100644
index 0000000..58bdd13
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/media.metadata.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<bundle>
+ <component class="net.java.sip.communicator.impl.media.MediaServiceImpl">
+ <provides service="net.java.sip.communicator.service.media.MediaService"/>
+
+ <requires
+ service="net.java.sip.communicator.service.configuration.ConfigurationService"
+ filter=""
+ policy="static"
+ cardinality="1..1"
+ bind-method="setConfigurationService"
+ unbind-method="unsetConfigurationService"
+ />
+ </component>
+
+</bundle>
diff --git a/src/net/java/sip/communicator/impl/netaddr/.#NetworkAddressManagerServiceImpl.java.1.6 b/src/net/java/sip/communicator/impl/netaddr/.#NetworkAddressManagerServiceImpl.java.1.6
new file mode 100644
index 0000000..7ef72a9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/.#NetworkAddressManagerServiceImpl.java.1.6
@@ -0,0 +1,562 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.netaddr;
+
+import java.net.*;
+import java.util.Enumeration;
+
+import net.java.sip.communicator.util.*;
+import net.java.stun4j.client.SimpleAddressDetector;
+import net.java.stun4j.StunAddress;
+import net.java.stun4j.StunException;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.configuration.event.*;
+import net.java.sip.communicator.service.configuration.*;
+
+
+
+
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public class NetworkAddressManagerServiceImpl
+ implements NetworkAddressManagerService, PropertyChangeListener
+{
+ private static Logger logger = Logger.getLogger(NetworkAddressManagerServiceImpl.class);
+
+ // General properties for the Network Address Manager
+ private static final String PROP_STUN_SERVER_ADDRESS
+ = "net.java.sip.communicator.STUN_SERVER_ADDRESS";
+ private static final String PROP_STUN_SERVER_PORT
+ = "net.java.sip.communicator.STUN_SERVER_PORT";
+ private static final String PROP_PREF_IPV6
+ = "java.net.preferIPv6Addresses";
+ private static final String PROP_PREF_IPV4
+ = "java.net.preferIPv4Stack";
+ private static final String PROP_PREFERRED_NET_ADDRESS
+ = "net.java.sip.communicator.common.PREFERRED_NETWORK_ADDRESS";
+ private static final String PROP_PREFERRED_NET_IFACE
+ = "net.java.sip.communicator.common.PREFERRED_NETWORK_INTERFACE";
+
+ //reference to the bundles used in this class
+ private ConfigurationService configurationService = null;
+ private NetworkAddressManagerService networkAddressManagerService= null;
+
+
+ private SimpleAddressDetector detector = null;
+ private boolean useStun = true;
+ private static final int RANDOM_PORT = 55055;
+ private static final String WINDOWS_AUTO_CONFIGURED_ADDRESS_PREFIX = "169";
+
+
+
+ /**
+ * When
+ *
+ */
+ public void propertyChange(PropertyChangeEvent event)
+ {
+ try
+ {
+ logger.logEntry();
+ if(event.getPropertyName()==PROP_STUN_SERVER_ADDRESS)
+ {
+ logger.debug(PROP_STUN_SERVER_ADDRESS + "Change state");
+ //Do an action
+ start();
+
+ }
+ else if(event.getPropertyName()==PROP_STUN_SERVER_PORT)
+ {
+ logger.debug(PROP_STUN_SERVER_PORT + "Change state");
+ //Do an action
+ start();
+
+ }
+ else
+ {
+ logger.debug("Something Change state but it is "
+ +"not determine what !");
+ start();
+ }
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+
+ /**
+ * The constructor nothing to do now, because we don't have access to the
+ * Configuration service yet
+ */
+ public NetworkAddressManagerServiceImpl()
+ {
+
+ // put a listener on propertyStunServerAddress and
+ //propertyStunServerPort properties
+ // set them to null il tey doesn't exist
+
+ }
+
+ /**
+ * get a reference to the configuration service
+ * and add listeners on propertyStunServerAddress and propertyStunServerPort
+ * @param configuration ConfigurationService reference to the bundle
+ * configuration service
+ */
+ protected void setConfigurationService(ConfigurationService configuration)
+ {
+ configurationService = configuration;
+
+ try
+ {
+ logger.logEntry();
+ configurationService.addPropertyChangeListener(
+ PROP_STUN_SERVER_ADDRESS,this);
+ configurationService.addPropertyChangeListener(
+ PROP_STUN_SERVER_PORT,this);
+ configurationService.addPropertyChangeListener(
+ PROP_PREF_IPV6,this);
+ configurationService.addPropertyChangeListener(
+ PROP_PREF_IPV4,this);
+ }
+ catch(Exception e)
+ {
+ logger.error("NetworkAddressManagerServiceImpl "
+ +"problem on listem properties : "+ e);
+ }
+
+
+
+
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Initializes the address manager and any underlying libs.
+ *
+ */
+ public void start()
+ {
+ try
+ {
+ logger.logEntry();
+ // init stun
+ //InetAddress stunAddressStr = null;
+ String stunAddressStr = null;
+ int port = -1;
+
+ try
+ {
+ stunAddressStr =(String) configurationService.getProperty(
+ PROP_STUN_SERVER_ADDRESS);
+ Integer portItr =(Integer) configurationService.getProperty(
+ PROP_STUN_SERVER_PORT);
+
+ // in case the user prefers ipv6 addresses we don't want
+ // to use stun
+ boolean preferIPv6Addresses ;
+ if(configurationService.getProperty(PROP_PREF_IPV6) == null
+ || (((Boolean)configurationService.getProperty(
+ PROP_PREF_IPV6)).booleanValue())==false)
+ {
+ preferIPv6Addresses = false;
+ }
+ else
+ {
+ preferIPv6Addresses = true;
+ }
+
+ if (stunAddressStr == null
+ || portItr == null
+ || preferIPv6Addresses)
+ {
+ useStun = false;
+
+ //don't throw an exception as this is most probably the user
+ //that doesn't want stun
+ //throw new Exception("STUN address or port were null");
+ return;
+ }
+ else
+ useStun = true;
+
+ port = portItr.intValue();
+
+ }
+ catch (Throwable ex)
+ {
+ logger.error("Failed to init STUN service and it will "
+ +"stay disabled. Error was:",ex);
+ useStun = false;
+ }
+ try
+ {
+ detector = new SimpleAddressDetector(
+ new StunAddress(stunAddressStr,port));
+ }
+ catch(Exception e)
+ {
+ logger.debug("can't create the StunDetector ! "+e);
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Created a STUN Address detector for the "
+ +"following STUN server: "
+ + stunAddressStr + ":" + port);
+ try {
+ detector.start();
+ logger.debug("STUN server started;");
+ }
+ catch (StunException ex) {
+ logger.error(
+ "Failed to start the STUN Address Detector at address:"
+ +stunAddressStr + ":" + port, ex);
+ detector = null;
+ useStun = false;
+ }
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+
+
+ /**
+ *
+ * @return an InetAddress instance representing the local host or null
+ * if no IP address for the host could be found
+ */
+ public InetAddress getLocalHost()
+ {
+ return getLocalHost(true);
+ }
+
+
+ /**
+ * Returns a localhostAddress.
+ *
+ * @param anyAddressIsAccepted is 0.0.0.0 accepted as a return value.
+ * @return the address that was detected the address of the localhost.
+ */
+ public InetAddress getLocalHost(boolean anyAddressIsAccepted)
+ {
+ try
+ {
+ logger.logEntry();
+ // (though InetAddress itself is not really mobile but in case it
+ //gets fixed).
+ InetAddress localHost = null;
+ InetAddress mappedAddress = null;
+ InetAddress linkLocalAddress = null;
+ InetAddress publicAddress = null;
+ String selectedInterface = null;
+
+ boolean preferIPv4Stack ;
+ if(configurationService.getProperty(PROP_PREF_IPV4) == null
+ || (((Boolean)configurationService.
+ getProperty(PROP_PREF_IPV4)).booleanValue())==false)
+ {
+ preferIPv4Stack = false;
+ }
+ else
+ {
+ preferIPv4Stack = true;
+ }
+
+
+ try
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("------------- NAMImpl.getLocalHost-----");
+ logger.debug("propertyIPv4Stack="
+ + configurationService.getProperty(PROP_PREF_IPV4));
+ logger.debug("propertyStunServerAddress = "
+ + configurationService.getProperty(
+ PROP_STUN_SERVER_ADDRESS));
+ logger.debug("propertyStunServerPort = "
+ + configurationService.getProperty(
+ PROP_STUN_SERVER_PORT));
+ logger.debug("propertIpV6Pref = "
+ + configurationService.getProperty(PROP_PREF_IPV6));
+ logger.debug("Use Stun :: "+useStun);
+ logger.debug("------------------------------");
+ }
+
+
+ //check whether we have a public address that matches one of
+ //the local interfaces if not - return the first one that
+ //is not the loopback
+ try
+ {
+ //retrieve a STUN binding if possible
+ if (useStun)
+ {
+ StunAddress stunMappedAddress =
+ queryStunServer(RANDOM_PORT);
+
+ if(stunMappedAddress == null)
+ {
+ mappedAddress = null;
+ }
+ else
+ {
+ mappedAddress = queryStunServer(RANDOM_PORT).
+ getSocketAddress().getAddress();
+ }
+ return mappedAddress;
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.error("manager.useStun error .. "
+ +"continuing without", ex);
+ }
+
+ Enumeration localIfaces =
+ NetworkInterface.getNetworkInterfaces();
+
+ //interfaces loop
+ interfaces_loop:
+ while (localIfaces.hasMoreElements())
+ {
+ NetworkInterface iFace =
+ (NetworkInterface) localIfaces.nextElement();
+ Enumeration addresses = iFace.getInetAddresses();
+
+ //addresses loop
+ while (addresses.hasMoreElements()) {
+ InetAddress address =
+ (InetAddress) addresses.nextElement();
+ //ignore link local addresses
+ if (!address.isAnyLocalAddress()
+ && !address.isLinkLocalAddress()
+ && !address.isLoopbackAddress()
+ && !isWindowsAutoConfiguredIPv4Address(address)) {
+ if (mappedAddress != null
+ && mappedAddress.equals(address)) {
+ if (logger.isDebugEnabled())
+ logger.debug("Returninng localhost: Mapped "
+ + "address = Public address = "
+ + address);
+ //the address matches the one seen by the STUN
+ //server no doubt that it's a working public
+ //address.
+
+ return address;
+ }
+ else if (isLinkLocalIPv4Address(address))
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found Linklocal ipv4 address "
+ + address);
+ linkLocalAddress = address;
+ }
+ else {
+ if (logger.isDebugEnabled())
+ logger.debug("Found public address "
+ + address);
+
+ String preferredAddr =
+ (String)configurationService.getProperty(
+ PROP_PREFERRED_NET_ADDRESS);
+ String preferredIface =
+ (String)configurationService.getProperty(
+ PROP_PREFERRED_NET_IFACE);
+
+
+ if (// bail out if we already have the address
+ // chosen by the user
+ ( publicAddress != null
+ && preferredAddr!= null
+ && preferredAddr.equals(
+ publicAddress.getHostAddress()))
+ //bail out if we already have an address on
+ //an interface chosen by the user
+ || (publicAddress != null
+ && selectedInterface != null
+ && preferredIface != null
+ && preferredIface.equals(
+ selectedInterface))
+ //in case we have an ipv4 addr and don't
+ //want to change it for an ipv6
+ || (publicAddress != null
+ && publicAddress instanceof Inet4Address
+ && address instanceof Inet6Address
+ && preferIPv4Stack)
+ //in case we have an ipv6 addr and don't
+ //want to change it for an ipv4
+ || (publicAddress != null
+ && publicAddress instanceof Inet6Address
+ && address instanceof Inet4Address
+ && !preferIPv4Stack)
+ )
+ {
+ continue;
+ }
+ publicAddress = address;
+ selectedInterface = iFace.getDisplayName();
+ }
+ }
+ }//addresses loop
+ }//interfaces loop
+ if (publicAddress != null) {
+ logger.debug("Returning public address");//debug
+ return publicAddress;
+ }
+ if (linkLocalAddress != null) {
+ logger.debug("Returning link local address");//debug
+ return linkLocalAddress;
+ }
+ if (anyAddressIsAccepted)
+ localHost = new InetSocketAddress(RANDOM_PORT).getAddress();
+ else
+ localHost = InetAddress.getLocalHost();
+ }
+ catch (Exception ex) {
+ logger.error("Failed to create localhost address, returning "
+ + "the any address (0.0.0.0)", ex);
+ //get the address part of an InetSocketAddress for a random port.
+ localHost = new InetSocketAddress(RANDOM_PORT).getAddress();
+ }
+ if (logger.isDebugEnabled())
+ logger.debug("Returning localhost address=" + localHost);
+ return localHost;
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+
+ /**
+ * Determines whether the address is the result of windows auto configuration.
+ * (i.e. One that is in the 169.254.0.0 network)
+ * @param add the address to inspect
+ * @return true if the address is autoconfigured by windows, false otherwise.
+ */
+ private static boolean isWindowsAutoConfiguredIPv4Address(InetAddress add)
+ {
+ return (add.getAddress()[0] & 0xFF) == 169
+ && (add.getAddress()[1] & 0xFF) == 254;
+ }
+
+ /**
+ * The method quesries a Stun server for a binding for the specified port.
+ * @param port the port from which a STUN message
+ * @return StunAddress
+ */
+ private StunAddress queryStunServer(int port)
+ {
+
+
+ try{
+ logger.logEntry();
+ StunAddress mappedAddress = null;
+ if (detector != null && useStun) {
+ try {
+ mappedAddress = detector.getMappingFor(port);
+ if (logger.isDebugEnabled())
+ logger.debug("For port:"
+ + port + "a Stun server returned the "
+ +"following mapping [" + mappedAddress);
+ }
+ catch (StunException ex) {
+ logger.error(
+ "Failed to retrive mapped address port:" +port, ex);
+ }
+ }
+ return mappedAddress;
+ }
+ finally{
+ logger.logExit();
+ }
+ }
+
+
+
+ /**
+ * Determines whether the address is an IPv4 link local address. IPv4 link
+ * local addresses are those in the following networks:
+ *
+ * 10.0.0.0 to 10.255.255.255
+ * 172.16.0.0 to 172.31.255.255
+ * 192.168.0.0 to 192.168.255.255
+ *
+ * @param add the address to inspect
+ * @return true if add is a link local ipv4 address and false if not.
+ */
+ private static boolean isLinkLocalIPv4Address(InetAddress add)
+ {
+ if(add instanceof Inet4Address)
+ {
+ byte address[] = add.getAddress();
+ if ( (address[0] & 0xFF) == 10)
+ return true;
+ if ( (address[0] & 0xFF) == 172
+ && (address[1] & 0xFF) >= 16 && address[1] <= 31)
+ return true;
+ if ( (address[0] & 0xFF) == 192
+ && (address[1] & 0xFF) == 168)
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Tries to obtain a mapped/public address for the specified port.
+ *
+ * @param port the port whose mapping we are interested in.
+ * @return a public address corresponding to the specified port or null
+ * if all attempts to retrieve such an address have failed.
+ */
+ public InetSocketAddress getPublicAddressFor(int port)
+ {
+ try {
+ logger.logEntry();
+ if (!useStun) {
+ logger.debug(
+ "Stun is disabled, skipping mapped address recovery.");
+ return new InetSocketAddress(getLocalHost(), port);
+ }
+ StunAddress mappedAddress = queryStunServer(port);
+ InetSocketAddress result = null;
+ if (mappedAddress != null)
+ result = mappedAddress.getSocketAddress();
+ else {
+ //Apparently STUN failed. Let's try to temporarily disble it
+ //and use algorithms in getLocalHost(). ... We should probably
+ //eveng think about completely disabling stun, and not only
+ //temporarily.
+ //Bug report - John J. Barton - IBM
+ InetAddress localHost = getLocalHost(false);
+ result = new InetSocketAddress(localHost, port);
+ }
+ if (logger.isDebugEnabled())
+ logger.debug("Returning mapping for port:"
+ + port +" as follows: " + result);
+ return result;
+ }
+ finally {
+ logger.logExit();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/.cvsignore b/src/net/java/sip/communicator/impl/netaddr/.cvsignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/.cvsignore
diff --git a/src/net/java/sip/communicator/impl/netaddr/Activator.java b/src/net/java/sip/communicator/impl/netaddr/Activator.java
new file mode 100644
index 0000000..ebc2978
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/Activator.java
@@ -0,0 +1,80 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.netaddr;
+
+import org.osgi.framework.*;
+import net.java.sip.communicator.service.configuration.ConfigurationService;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * The activator manage the the bundles between OSGi framework and the
+ * Network address manager
+ *
+ * @author Emil Ivov
+ * @author Pierre Floury
+ */
+public class Activator
+ implements BundleActivator
+{
+ private static Logger logger =
+ Logger.getLogger(NetworkAddressManagerServiceImpl.class);
+
+ private NetworkAddressManagerServiceImpl networkAMS = null;
+
+ /**
+ * Creates a NetworkAddressManager, starts it, and registers it as a
+ * NetworkAddressManagerService.
+ *
+ * @param bundleContext OSGI bundle context
+ * @throws Exception if starting the NetworkAddressManagerFails.
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ try{
+
+ logger.logEntry();
+ // get the config service
+ ServiceReference refConfig = bundleContext.getServiceReference(
+ ConfigurationService.class.getName());
+
+ ConfigurationService configurationService = (ConfigurationService)
+ bundleContext.getService(refConfig);
+
+ //Create and start the network address manager.
+ networkAMS =
+ new NetworkAddressManagerServiceImpl(configurationService);
+
+ // give references to the NetworkAddressManager implementation
+ networkAMS.start();
+
+ logger.info("Network Address Manager ...[ STARTED ]");
+
+ bundleContext.registerService(
+ NetworkAddressManagerService.class.getName(), networkAMS, null);
+
+ logger.info("Network Address Manager Service ...[REGISTERED]");
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Stops the Networ Address Manager bundle
+ *
+ * @param bundleContext the OSGI bundle context
+ *
+ */
+ public void stop(BundleContext bundleContext)
+ {
+ if(networkAMS != null)
+ networkAMS.stop();
+ logger.info("Network Address Manager Service ...[STOPED]");
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/AddressDiagnosticsKit.java b/src/net/java/sip/communicator/impl/netaddr/AddressDiagnosticsKit.java
new file mode 100644
index 0000000..4ed1a72
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/AddressDiagnosticsKit.java
@@ -0,0 +1,384 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import net.java.sip.communicator.util.*;
+import java.net.*;
+import net.java.stun4j.*;
+import net.java.stun4j.stack.*;
+import net.java.stun4j.message.*;
+import net.java.stun4j.attribute.*;
+
+/**
+ * Runs a separate thread of diagnostics for a given network address. The
+ * diagnostics thread would discover NAT bindings through stun, update bindings
+ * lifetime test connectivity and etc.
+ *
+ * @author Emil Ivov
+ */
+public class AddressDiagnosticsKit
+ extends Thread
+{
+ private static final Logger logger =
+ Logger.getLogger(AddressDiagnosticsKit.class);
+
+ public static final int DIAGNOSTICS_STATUS_OFF = 1;
+ public static final int DIAGNOSTICS_STATUS_DISOVERING_CONFIG = 2;
+ public static final int DIAGNOSTICS_STATUS_RESOLVING = 3;
+ public static final int DIAGNOSTICS_STATUS_COMPLETED = 4;
+ public static final int DIAGNOSTICS_STATUS_DISOVERING_BIND_LIFETIME = 5;
+ public static final int DIAGNOSTICS_STATUS_TERMINATED = 6;
+
+ private int diagnosticsStatus = DIAGNOSTICS_STATUS_OFF;
+
+ /**
+ * These are used by (to my knowledge) mac and windows boxes when dhcp
+ * fails and are only usable with other boxes using the same address
+ * in the same net segment. That's why they get their low preference.
+ */
+ private static final AddressPreference ADDR_PREF_LOCAL_IPV4_AUTOCONF
+ = new AddressPreference(40);
+
+ /**
+ * Local IPv6 addresses are assigned by default to any network iface running
+ * an ipv6 stack. Theya are one of our last resorts since an internet
+ * connected node would have generally configured sth else as well.
+ */
+ private static final AddressPreference ADDR_PREF_LOCAL_IPV6
+ = new AddressPreference(40);
+
+ /**
+ * Local IPv4 addresses are either assigned by DHCP or manually configured
+ * which means that even if they're unresolved to a globally routable
+ * address they're still there for a reason (let the reason be ...) and this
+ * reason might very well be purposeful so they should get a preference
+ * higher than local IPv6 (even though I'm an IPv6 fan :) )
+ */
+ private static final AddressPreference ADDR_PREF_PRIVATE_IPV4
+ = new AddressPreference(50);
+
+ /**
+ * Global IPv4 Addresses are a good think when they work. We are therefore
+ * setting a high preference that will then be corrected by.
+ */
+ private static final AddressPreference ADDR_PREF_GLOBAL_IPV4
+ = new AddressPreference(60);
+
+ /**
+ * There are many reasons why global IPv6 addresses should have the highest
+ * preference. A global IPv6 address is most often delivered through
+ * stateless address autoconfiguration which means an active router and
+ * might also mean an active net connection.
+ */
+ private static final AddressPreference ADDR_PREF_GLOBAL_IPV6
+ = new AddressPreference(70);
+
+ /**
+ * The address of the stun server to query
+ */
+ private StunAddress primaryStunServerAddress =
+ new StunAddress("stun01.sipphone.com", 3478);
+
+ /**
+ * The address pool entry that this kit is diagnosing.
+ */
+ private AddressPoolEntry addressEntry = null;
+
+ /**
+ * Specifies whether stun should be used or not.
+ * This field is updated during runtime to conform to the configuration.
+ */
+ private boolean useStun = true;
+
+ private StunClient stunClient = null;
+
+ /**
+ * The port to be used locally for sending generic stun queries.
+ */
+ static final int LOCAL_STUN_PORT = 55126;
+ private int bindRetries = 10;
+
+ public AddressDiagnosticsKit(AddressPoolEntry addressEntry)
+ {
+ this.addressEntry = addressEntry;
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_OFF);
+ }
+
+ /**
+ * Sets the current status of the address diagnostics process
+ * @param status int
+ */
+ private void setDiagnosticsStatus(int status)
+ {
+ this.diagnosticsStatus = status;
+ }
+
+ /**
+ * Returns the current status of this diagnosics process.
+ * @return int
+ */
+ public int getDiagnosticsStatus()
+ {
+ return this.diagnosticsStatus;
+ }
+
+ /**
+ * The diagnostics code itself.
+ */
+ public void run()
+ {
+ logger.debug("Started a diag kit for entry: " + addressEntry);
+
+ //implements the algorithm from AssigningAddressPreferences.png
+
+ setDiagnosticsStatus(this.DIAGNOSTICS_STATUS_DISOVERING_CONFIG);
+
+ InetAddress address = addressEntry.getInetAddress();
+
+ //is this an ipv6 address
+ if (addressEntry.isIPv6())
+ {
+ if (addressEntry.isLinkLocal())
+ {
+ addressEntry.setAddressPreference(ADDR_PREF_LOCAL_IPV6);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ return;
+ }
+
+ if (addressEntry.is6to4())
+ {
+ //right now we don't support these. we should though ... one day
+ addressEntry.setAddressPreference(AddressPreference.MIN);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ return;
+ }
+
+ //if we get here then we are a globally routable ipv6 addr
+ addressEntry.setAddressPreference(ADDR_PREF_GLOBAL_IPV6);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_COMPLETED);
+ //should do some connectivity testing here and proceed with firewall
+ //discovery but since stun4j does not support ipv6 yet, this too
+ //will happen another day.
+ return;
+ }
+
+ //from now on we're only dealing with IPv4
+ if (addressEntry.isIPv4LinkLocalAutoconf())
+ {
+ //not sure whether these are used for anything.
+ addressEntry.setAddressPreference(AddressPreference.MIN);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ return;
+ }
+
+ //first try and see what we can infer from just looking at the
+ //address
+ if (addressEntry.isLinkLocalIPv4Address())
+ {
+ addressEntry.setAddressPreference(ADDR_PREF_PRIVATE_IPV4);
+ }
+ else
+ {
+ //public address
+ addressEntry.setAddressPreference(ADDR_PREF_GLOBAL_IPV4);
+ }
+
+ if (!useStun)
+ {
+ //if we're configured not to run stun - we're done.
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ return;
+ }
+
+ //start stunning
+ for(int i = 0; i < bindRetries; i++){
+ StunAddress localStunAddress = new StunAddress(
+ address, 1024 + (int) (Math.random() * 64512));
+ try
+ {
+
+ stunClient = new StunClient(localStunAddress);
+ stunClient.start();
+ logger.debug("Successfully started StunClient for "
+ + localStunAddress + ".");
+ break;
+ }
+ catch (StunException ex)
+ {
+ if (ex.getCause() instanceof SocketException
+ && i < bindRetries)
+ {
+ logger.debug("Failed to bind to "
+ + localStunAddress + ". Retrying ...");
+ logger.debug("Exception was ", ex);
+ continue;
+ }
+ logger.error("Failed to start a stun client for address entry ["
+ + addressEntry.toString()+"]:"
+ +localStunAddress.getPort() + ". Ceasing attempts",
+ ex);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ return;
+ }
+ }
+ //De Stun Test I
+ StunMessageEvent event = null;
+ try
+ {
+ event = stunClient.doStunTestI(
+ primaryStunServerAddress);
+ }
+ catch (StunException ex)
+ {
+ logger.error("Failed to perform STUN Test I for address entry"
+ + addressEntry.toString(), ex);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ if(event == null)
+ {
+ //didn't get a response - we either don't have connectivity or the
+ //server is down
+ /** @todo if possible try another stun server here. we should
+ * support multiple stun servers*/
+ logger.debug("There seems to be no inet connectivity for "
+ + addressEntry);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ logger.debug("stun test 1 failed");
+ return;
+ }
+
+ //the moment of the truth - are we behind a NAT?
+ boolean isPublic;
+ Message stunResponse = event.getMessage();
+
+ Attribute mappedAttr = stunResponse.getAttribute(Attribute.MAPPED_ADDRESS);
+
+ StunAddress mappedAddrFromTestI = ((MappedAddressAttribute)mappedAttr).getAddress();
+ Attribute changedAddressAttributeFromTestI
+ = stunResponse.getAttribute(Attribute.CHANGED_ADDRESS);
+ StunAddress secondaryStunServerAddress =
+ ((ChangedAddressAttribute)changedAddressAttributeFromTestI).
+ getAddress();
+
+ /** @todo verify whether the stun server returned the same address for
+ * the primary and secondary server and act accordingly
+ * */
+
+ if(mappedAddrFromTestI == null){
+ logger.error(
+ "Stun Server did not return a mapped address for entry "
+ + addressEntry.toString());
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ return;
+ }
+
+ if(mappedAddrFromTestI.equals(event.getSourceAccessPoint().getAddress()))
+ {
+ isPublic = true;
+ }
+ else
+ {
+ isPublic = false;
+ }
+
+ //do STUN Test II
+ try
+ {
+ event = stunClient.doStunTestII(primaryStunServerAddress);
+ }
+ catch (StunException ex)
+ {
+ logger.error("Failed to perform STUN Test II for address entry"
+ + addressEntry.toString(), ex);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ logger.debug("stun test 2 failed");
+ return;
+ }
+
+ if(event != null){
+ logger.error("Secondary STUN server is down"
+ + addressEntry.toString());
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ //might mean that either the secondary stun server is down
+ //or that we are behind a restrictive firewall. Let's find out
+ //which.
+ try
+ {
+ event = stunClient.doStunTestI(secondaryStunServerAddress);
+ logger.debug("stun test 1 succeeded with s server 2");
+ }
+ catch (StunException ex)
+ {
+ logger.error("Failed to perform STUN Test I for address entry"
+ + addressEntry.toString(), ex);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ if (event == null)
+ {
+ //secondary stun server is down
+ logger.error("Secondary STUN server is down"
+ + addressEntry.toString());
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ //we are at least behind a port restricted nat
+
+ stunResponse = event.getMessage();
+ mappedAttr = stunResponse.getAttribute(Attribute.MAPPED_ADDRESS);
+ StunAddress mappedAddrFromSecServer =
+ ((MappedAddressAttribute)mappedAttr).getAddress();
+
+ if(!mappedAddrFromTestI.equals(mappedAddrFromSecServer))
+ {
+ //secondary stun server is down
+ logger.debug("We are behind a symmetric nat"
+ + addressEntry.toString());
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ //now let's run test III so that we could guess whether or not we're
+ //behind a port restricted nat/fw or simply a restricted one.
+ try
+ {
+ event = stunClient.doStunTestIII(primaryStunServerAddress);
+ logger.debug("stun test 3 succeeded with s server 1");
+ }
+ catch (StunException ex)
+ {
+ logger.error("Failed to perform STUN Test III for address entry"
+ + addressEntry.toString(), ex);
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ if (event == null)
+ {
+ logger.debug("We are behind a port restricted NAT or fw"
+ + addressEntry.toString());
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ return;
+ }
+
+ logger.debug("We are behind a restricted NAT or fw"
+ + addressEntry.toString());
+ setDiagnosticsStatus(DIAGNOSTICS_STATUS_TERMINATED);
+ stunClient.shutDown();
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/netaddr/AddressPool.java b/src/net/java/sip/communicator/impl/netaddr/AddressPool.java
new file mode 100644
index 0000000..e5b0941
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/AddressPool.java
@@ -0,0 +1,80 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import java.net.NetworkInterface;
+import java.net.InetAddress;
+import java.util.Enumeration;
+import net.java.sip.communicator.util.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * The class scans all local interfaces discovering all addresses, and starts
+ * constantly testing them one by one in order to verify their properties. It
+ * also orders the addresses, putting first those that it has determined to be
+ * more easily usable and that offer better chances of connection success.
+ *
+ * @author Emil Ivov
+ */
+public class AddressPool
+{
+ private static Logger logger =
+ Logger.getLogger(AddressPool.class);
+
+ private Map diagnosticsKits = new Hashtable();
+ private ArrayList addressEntries = new ArrayList();
+
+ public AddressPool()
+ {
+ super();
+ }
+
+ private void initPool()
+ {
+ Enumeration localIfaces = null;
+ try
+ {
+ localIfaces = NetworkInterface.getNetworkInterfaces();
+ }
+ catch (SocketException ex)
+ {
+ throw new RuntimeException(
+ "Failed to retrieve local interfaces!");
+ }
+
+ //loop over all local network interfaces
+ while (localIfaces.hasMoreElements())
+ {
+ NetworkInterface iFace =
+ (NetworkInterface) localIfaces.nextElement();
+
+ Enumeration addresses = iFace.getInetAddresses();
+
+ //addresses loop
+ while (addresses.hasMoreElements())
+ {
+ InetAddress address = (InetAddress) addresses.nextElement();
+
+ //we don't care about loopback addresses
+ if(address.isLoopbackAddress())
+ continue;
+
+ AddressPoolEntry addrEntry =
+ new AddressPoolEntry(address, iFace);
+ AddressDiagnosticsKit diagKit =
+ new AddressDiagnosticsKit(addrEntry);
+
+ addressEntries.add(addrEntry);
+ diagnosticsKits.put(addrEntry, diagKit);
+ diagKit.start();
+ } //addresses loop
+ } //interfaces loop
+ }
+
+ public static void main(String[] args)
+ {
+ AddressPool pool = new AddressPool();
+ pool.initPool();
+ }
+
+
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/AddressPoolEntry.java b/src/net/java/sip/communicator/impl/netaddr/AddressPoolEntry.java
new file mode 100644
index 0000000..897a725
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/AddressPoolEntry.java
@@ -0,0 +1,275 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import java.net.*;
+
+/**
+ * An entry in the Address Pool. An addresspool entry contains an address
+ * belonging to any of the local network interfaces together with properties
+ * that characterize them, such as - whether or not the address is publicly
+ * routable or not, It's corresponding NAT entry obtained by stun. The type of
+ * NAT that the address is located behind (if any). The lifetime of the bindings
+ * behind this NAT. Any TURN bindings. Whether or not TCP connections seem to be
+ * supported. Whether or not UDP connections seem to be supported, and etc. etc.
+ *
+ * Concerning the address, this is an immutable object, in other words, the
+ * address of a single entry is not supposed to change once it has been created.
+ * In case this address is modified while the application is running we'll
+ * rather have a new address entry instead of modifying this one. The only thing
+ * that can change about an address pool entry is its properties.
+ *
+ * @author Emil Ivov
+ */
+public class AddressPoolEntry
+{
+ private InetAddress address = null;
+
+ /**
+ * The AddressPreference qualifyer is used to indicate preference of this
+ * address compared to others available on the current host.
+ */
+ private AddressPreference preference;
+
+ /**
+ * Only used for ipv4 addresses. Actually it would have been better to use
+ * the isLinkLocal method of InetAddress but since it only works for ipv6
+ * we're using this one. in the case of an ip address
+ */
+ private boolean isLinkLocal = false;
+
+ private NetworkInterface ownerInterface = null;
+
+ private FirewallDescriptor firewallDescriptor = null;
+
+ private InetAddress turnAddress = null;
+
+ public AddressPoolEntry(InetAddress address, NetworkInterface ownerIface)
+ {
+ if(address == null)
+ throw new NullPointerException("Address param cannot be null");
+ this.address = address;
+ this.ownerInterface = ownerIface;
+ }
+
+ /**
+ * Returns the ip address that this address pool entry represents.
+ * @return InetAddress
+ */
+ public InetAddress getInetAddress()
+ {
+ return address;
+ }
+
+ /**
+ * Determines whether or not the address pool entry represents an IPv6
+ * address.
+ * @return true if the address is ipv6 and false in case of ipv4.
+ */
+ public boolean isIPv6()
+ {
+ return (address instanceof Inet6Address);
+ }
+
+ /**
+ * Determines whether this is a link local or publicly routable address.
+ * Works for both IPv4 and IPv6 addresses.
+ * @return true if the address is link local and thus not globally routable
+ * and false if otherwise.
+ */
+ public boolean isLinkLocal()
+ {
+ if( address instanceof Inet6Address){
+ if(address.isLinkLocalAddress()){
+ return true;
+ }
+ else{
+ return false;
+ }
+ }
+
+ return isLinkLocal;
+ }
+
+ /**
+ * Specifies whether or not the address is an IPv4 link local address.
+ * @param linkLocal true if t
+ */
+ void setLinkLocal(boolean linkLocal)
+ {
+ this.isLinkLocal = linkLocal;
+ }
+
+
+ /**
+ * Determines whether the address is the result of windows auto configuration.
+ * (i.e. One that is in the 169.254.0.0 network)
+ * @param add the address to inspect
+ * @return true if the address is autoconfigured by windows, false otherwise.
+ */
+ /**
+ * Determines whether the address is the result of windows auto configuration.
+ * (i.e. One that is in the 169.254.0.0 network)
+ * @param add the address to inspect
+ * @return true if the address is autoconfigured by windows, false otherwise.
+ */
+ public static boolean isIPv4LinkLocalAutoconf(InetAddress add)
+ {
+ return (add.getAddress()[0] & 0xFF) == 169
+ && (add.getAddress()[1] & 0xFF) == 254;
+ }
+
+ /**
+ * Determines whether the address encapsulated by this entry is the result of
+ * windows auto configuration (i.e. One that is in the 169.254.0.0 network)
+ * @return true if the address is autoconfigured by windows, false otherwise.
+ */
+ public boolean isIPv4LinkLocalAutoconf()
+ {
+ return isIPv4LinkLocalAutoconf(address);
+ }
+
+ /**
+ * Determines whether the address is an IPv4 link local address. IPv4 link
+ * local addresses are those in the following networks:
+ *
+ * 10.0.0.0 to 10.255.255.255
+ * 172.16.0.0 to 172.31.255.255
+ * 192.168.0.0 to 192.168.255.255
+ *
+ * @param add the address to inspect
+ * @return true if add is a link local ipv4 address and false if not.
+ */
+ public static boolean isLinkLocalIPv4Address(InetAddress add)
+ {
+ if(add instanceof Inet4Address)
+ {
+ byte address[] = add.getAddress();
+ if ( (address[0] & 0xFF) == 10)
+ return true;
+ if ( (address[0] & 0xFF) == 172
+ && (address[1] & 0xFF) >= 16 && address[1] <= 31)
+ return true;
+ if ( (address[0] & 0xFF) == 192
+ && (address[1] & 0xFF) == 168)
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+
+ /**
+ * Determines whether the address encapsulated by this entry is an IPv4 link
+ * local address. IPv4 link local addresses are those in the following
+ * networks:
+ *
+ * 10.0.0.0 to 10.255.255.255
+ * 172.16.0.0 to 172.31.255.255
+ * 192.168.0.0 to 192.168.255.255
+ *
+ * @return true if add is a link local ipv4 address and false if not.
+ */
+ public boolean isLinkLocalIPv4Address()
+ {
+ return isLinkLocalIPv4Address(this.address);
+ }
+
+ /**
+ * Determines whether the address encapsulated by this entry is an IPv6 link
+ * local address. IPv6 link local addresses are briefly those that start
+ * with fe80.
+ *
+ * @return true if add is a link local ipv6 address and false if not.
+ */
+ public boolean isLinkLocalIPv6Address()
+ {
+ return address instanceof Inet6Address && address.isLinkLocalAddress();
+ }
+
+ /**
+ * Determines whether this is the localhost address (127.0.0.1 or ::1).
+ * This is a simple wrapper of the InetAddress.isLoopbackAddress() method.
+ * @return true if this is and IPv6 or IPv4 loopback address and false
+ * otherwise.
+ */
+ public boolean isLoopback()
+ {
+ return address.isLoopbackAddress();
+ }
+
+ /**
+ * Determines whether the adderss encapsulated by this address entry is
+ * a globally routable inet address, or in other words is it possible
+ * (at least in theory) to directly send packets to it from any point of
+ * the internet.
+ * @return true if this is a public ip addr and false otherwise.
+ */
+ public boolean isGloballyRoutable()
+ {
+ return !isLinkLocalIPv6Address()
+ && !isIPv4LinkLocalAutoconf()
+ && !isLinkLocalIPv4Address()
+ && !isLoopback();
+ }
+
+ /**
+ * Determines whether the adderss encapsulated by this address entry is
+ * a 6to4 translation address (2002::/16)
+ *
+ * @return true if this is a 6to4 ip addr (belongs to 2002::/16) and false
+ * otherwise.
+ */
+ public boolean is6to4()
+ {
+ return address instanceof Inet6Address
+ && (address.getAddress()[0] & 0xff) == 0x20
+ && (address.getAddress()[0] & 0xc0) == 0x02;
+ }
+
+ /**
+ * Returns the interface that this address belongs to.
+ * @return a reference to the interface that this address belongs to.
+ */
+ public NetworkInterface getOwnerInterface()
+ {
+ return ownerInterface;
+ }
+
+ /**
+ * Returns a string representation of this address entry
+ * @return a String containing key characteristics of this address pool
+ * entry
+ */
+ public String toString()
+ {
+ return "AddressPoolEntry:"
+ + address.getHostAddress()
+ + "@"+getOwnerInterface().getDisplayName() + " "
+ + "isIPv6=" + isIPv6() + ", "
+ + "isLoopback=" + isLoopback() + ", "
+ + "isGloballyRoutable=" + isGloballyRoutable() + ", "
+ + "isLinkLocal=" + isLinkLocal()
+ + "AddressPreference=["+preference+"]";
+ }
+
+ /**
+ * Sets the AddressPreference that address diagnostics have calculated for
+ * the address corresponding to this entry.
+ * @param preference the preference to assign to this entry
+ */
+ void setAddressPreference(AddressPreference preference)
+ {
+ this.preference = preference;
+ }
+
+ /**
+ * Returns the AddressPreference assigned to this AddressEntry. The
+ * AddressPreference is what establishes an order in the "usability" of the
+ * addresses on the local machine.
+ * @return AddressPreference the AddressPreference assigned to this entry.
+ */
+ public AddressPreference getAddressPreference()
+ {
+ return this.preference;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/AddressPreference.java b/src/net/java/sip/communicator/impl/netaddr/AddressPreference.java
new file mode 100644
index 0000000..612e019
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/AddressPreference.java
@@ -0,0 +1,109 @@
+package net.java.sip.communicator.impl.netaddr;
+
+/**
+ * The AddressPreference class is used to assign preference to the various
+ * network addresses on a host. Preferencies are in essence integers that
+ * may vary between MAX_PREF and MIN_PREF, where MIN_PREF indicates low or
+ * inexisting connectivity through the specified address and MAX_PREF -
+ * complete, flowless open internet access (the perfect connection ;-) )
+ *
+ * @author Emil Ivov
+ */
+public class AddressPreference
+ implements Comparable
+{
+ public static final int MAX_PREF = 100;
+ public static final int MIN_PREF = 0;
+
+ public static final AddressPreference MAX = new AddressPreference(MAX_PREF);
+ public static final AddressPreference MIN = new AddressPreference(MIN_PREF);
+
+ /**
+ * The numerical value of this AddressPreference instance.
+ */
+ private int preference = (MAX_PREF - MIN_PREF)/2;
+
+ /**
+ * Creates an AddressPreference instance with the specified preference.
+ * @param preference the preference integer corresponding to this
+ * AddressPreference
+ */
+ AddressPreference(int preference)
+ {
+ this.preference = preference;
+ }
+
+ /**
+ * Creates an AddressPreference object with a default preference value.
+ */
+ AddressPreference()
+ {
+ }
+
+ /**
+ * Sets the preference value of this AddressPreference instance to be
+ * @param preference int
+ */
+ void setPreference(int preference)
+ {
+ this.preference = preference;
+ }
+
+
+ /**
+ * Returns the exact preference value of this AddressPreference instance.
+ * @return the exact preference value (an ineteger between MAX_PREF and
+ * MIN_PREF) representing this AddressPreference instance.
+ */
+ public int getPreference()
+ {
+ return preference;
+ }
+
+ /**
+ * Compares this address preference with the specified object for order.
+ * Returns a negative integer, zero, or a positive integer as this
+ * AddressPreference is less than, equal to, or greater than the specified
+ * object.<p>
+ *
+ * @param o the Object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ *
+ * @throws ClassCastException if the specified object's type is not an
+ * instance or a descendant of AddressPreference.
+ */
+ public int compareTo(Object o)
+ {
+ AddressPreference other = (AddressPreference)o;
+
+ return this.preference - other.preference;
+ }
+
+ /**
+ * Returns true if <code>obj</code> is the same object as this
+ * AddressPreference or is at least an instance of AddressPreference and
+ * has the same numerical value. In all other cases the method returns
+ * false.
+ * @param obj the object to compare with
+ * @return true if both objects represent the same preference value and
+ * false otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if (! (obj instanceof AddressPreference)
+ || obj == null)
+ return false;
+
+ if (obj == this
+ || ((AddressPreference)obj).preference == preference )
+ return true;
+
+ return false;
+ }
+
+ public String toString()
+ {
+ return "preference="+getPreference();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/BlockingRequestSender.java b/src/net/java/sip/communicator/impl/netaddr/BlockingRequestSender.java
new file mode 100644
index 0000000..430b44a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/BlockingRequestSender.java
@@ -0,0 +1,96 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import net.java.stun4j.*;
+import net.java.stun4j.message.*;
+import net.java.stun4j.stack.*;
+
+/**
+ * A utility used to flatten the multithreaded architecture of the Stack
+ * and execute the discovery process in a synchronized manner. Roughly what
+ * happens here is:
+ *
+ * ApplicationThread:
+ * sendMessage()
+ * wait();
+ *
+ * StackThread:
+ * processMessage/Timeout()
+ * {
+ * saveMessage();
+ * notify();
+ * }
+ *
+ *
+ * <p>Organisation: <p> Louis Pasteur University, Strasbourg, France</p>
+ * <p>Network Research Team (http://www-r2.u-strasbg.fr)</p></p>
+ * @author Emil Ivov
+ * @version 0.1
+ */
+class BlockingRequestSender
+ implements ResponseCollector
+{
+ private StunProvider stunProvider = null;
+ private NetAccessPointDescriptor apDescriptor = null;
+
+ StunMessageEvent responseEvent = null;
+
+ BlockingRequestSender(StunProvider stunProvider,
+ NetAccessPointDescriptor apDescriptor)
+ {
+ this.stunProvider = stunProvider;
+ this.apDescriptor = apDescriptor;
+ }
+
+ /**
+ * Saves the message event and notifies the discoverer thread so that
+ * it may resume.
+ * @param evt the newly arrived message event.
+ */
+ public synchronized void processResponse(StunMessageEvent evt)
+ {
+ this.responseEvent = evt;
+ notifyAll();
+ }
+
+ /**
+ * Notifies the discoverer thread when a message has timeouted so that
+ * it may resume and consider it as unanswered.
+ */
+ public synchronized void processTimeout()
+ {
+ notifyAll();
+ }
+
+ /**
+ * Sends the specified request and blocks until a response has been
+ * received or the request transaction has timed out.
+ * @param request the reuqest to send
+ * @param serverAddress the request destination address
+ * @return the event encapsulating the response or null if no response
+ * has been received.
+ * @throws StunException NETWORK_ERROR or other if we fail to send
+ * the message
+ */
+ public synchronized StunMessageEvent sendRequestAndWaitForResponse(
+ Request request,
+ StunAddress serverAddress)
+ throws StunException
+ {
+ stunProvider.sendRequest(request, serverAddress, apDescriptor,
+ BlockingRequestSender.this);
+
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException ex)
+ { /** @todo log */
+ ex.printStackTrace();
+ }
+
+ StunMessageEvent res = responseEvent;
+ responseEvent = null; //prepare for next message
+
+ return res;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/FirewallDescriptor.java b/src/net/java/sip/communicator/impl/netaddr/FirewallDescriptor.java
new file mode 100644
index 0000000..4173929
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/FirewallDescriptor.java
@@ -0,0 +1,204 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import java.net.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * todo: add a type for the open internet
+ *
+ *
+ * @author Emil Ivov
+ */
+public class FirewallDescriptor
+{
+ private static final Logger logger =
+ Logger.getLogger(FirewallDescriptor.class);
+
+ /**
+ * The amount of preference points that a firewall corresponding to this
+ * descriptor should remove from the address preference.
+ */
+ private AddressPreference preferenceSubtrahend =
+ new AddressPreference(AddressPreference.MIN_PREF);
+
+
+ /**
+ * Means no firewall or nat. In the case of a privvate IPv4 address this
+ * would meand no internet connectivity through this address. The same
+ * applies to IPv6 link local addresses. In the case of a public (IPv4 or
+ * IPv6) address this means that there is unlimited connectivity.
+ */
+ public static final int TYPE_OPEN_INTERNET = 1;
+
+ /**
+ * Full cone NAT or firewall.
+ */
+ public static final int TYPE_FULL_CONE = 2;
+
+ /**
+ * Restricted cone NAT or firewall.
+ */
+ public static final int TYPE_RESTRICTED_CONE = 3;
+
+ /**
+ * Port restricted cone NAT or firewall.
+ */
+ public static final int TYPE_PORT_RESTRICTED_CONE = 4;
+
+ /**
+ * Symmetric NAT or firewall.
+ */
+ public static final int TYPE_SYMMETRIC = 5;
+
+ /**
+ * Determines firewall type. Could be one of symmetric, full cone,
+ * restricted cone, port restricted cone.
+ */
+ private int type = -1;
+
+ /**
+ * The time (in seconds) that address port bindings remain active on this
+ * firewall without the node sendind any packets. Bindings may and most
+ * probably will change during runtime. They are initially set to be equal
+ * to net.java.sip.communicator.service.netaddr.INITIAL_BINDINGS_LIFETIME.
+ */
+ private int bindingsLifetime = 30;
+
+ /**
+ * Indicates whether or not the firewall corresponding to this descriptor
+ * is also acting as NAT (are we using a globally routable ip address or
+ * not).
+ */
+ private boolean isTranslatingAddresses = false;
+
+ /**
+ * The public IP address of the firewall. In the case of a NAT this is
+ * the address that other would have to use to contact us.
+ */
+ private InetAddress publicAddress = null;
+
+ /**
+ * Constructs an empty firewall descirptor
+ */
+ FirewallDescriptor()
+ {
+ super();
+ }
+
+ /**
+ * Set the type of this firewall.
+ * @param type the type of the firewall referenced by this descriptor.
+ */
+ void setType(int type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Returns the type of the firewall referenced by this desciptor
+ * @return the type of the firewall referenced by this desciptor. One of the
+ * TYPE_XXX fields of this class.
+ */
+ public int getType()
+ {
+ return this.type;
+ }
+
+ /**
+ * Sets the address preference subtrahend corresponding to the firewall
+ * referenced by this descriptor. The subtrahend is a value that is
+ * subtracted from AddressPreference-s of addresses behind this firewall.
+ *
+ * @param subtrahend the amount of address preference points that need to
+ * be subtracted from address preferences of oaddresses behind this
+ * firewall.
+ */
+ void setPreferenceSubtrahend(AddressPreference subtrahend)
+ {
+ this.preferenceSubtrahend = subtrahend;
+ }
+
+ /**
+ * Returns the address preference subtrahend corresponding to the firewall
+ * referenced by this descriptor. The subtrahend is a value that is
+ * subtracted from AddressPreference-s of addresses behind this firewall.
+ *
+ * @return the amount of address preference points that need to
+ * be subtracted from address preferences of oaddresses behind this
+ * firewall.
+ */
+ public AddressPreference getAddressPreferenceSubtrahend()
+ {
+ return this.preferenceSubtrahend;
+ }
+
+ /**
+ * Sets the public IP address of the firewall. In the case of a NAT this is
+ * the address that others would have to use to contact us.
+ *
+ * @param address the ip address of the nat
+ */
+ void setPublicAddress(InetAddress address)
+ {
+ this.publicAddress = address;
+ }
+
+ /**
+ * Returns the public IP address of the firewall. In the case of a NAT this
+ * is the address that others would have to use to contact us.
+ *
+ * @return the ip address of the nat
+ */
+ public InetAddress getPublicAddress()
+ {
+ return this.publicAddress;
+ }
+
+ /**
+ * Sets the time (in seconds) that address port bindings remain active on
+ * this firewall without the node sendind any packets. Bindings may and most
+ * probably will change during runtime. They are initially set to be equal
+ * to net.java.sip.communicator.service.netaddr.INITIAL_BINDINGS_LIFETIME.
+ *
+ * @param lifetime the number of seconds that bindings on this firewall
+ * remain active
+ */
+ void setBindingsLifetime(int lifetime)
+ {
+ this.bindingsLifetime = lifetime;
+ }
+
+ /**
+ * Returns the time (in seconds) that address port bindings remain active on
+ * this firewall without the node sendind any packets. Bindings may and most
+ * probably will change during runtime. They are initially set to be equal
+ * to net.java.sip.communicator.service.netaddr.INITIAL_BINDINGS_LIFETIME.
+ *
+ * @return lifetime the number of seconds that bindings on this firewall
+ * remain active
+ */
+ public int getBindingsLifetime()
+ {
+ return this.bindingsLifetime;
+ }
+
+ /**
+ * Specifies whether this is an address translating firewall (NAT) or not.
+ * @param isNAT a boolean specifying whether the firewall referenced by this
+ * descriptor is a NAT.
+ */
+ void setTranslatingAddresses(boolean isNAT)
+ {
+ this.isTranslatingAddresses = isNAT;
+ }
+
+ /**
+ * Determines whether this is an address translating firewall (NAT) or not.
+ * @return true if the firewall referenced by this descriptor is a NAT and
+ * false otherwise.
+ */
+ public boolean isTranslatingAddresses()
+ {
+ return isTranslatingAddresses;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java b/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
new file mode 100644
index 0000000..8409033
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
@@ -0,0 +1,634 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.netaddr;
+
+import java.net.*;
+import java.util.Enumeration;
+
+import net.java.sip.communicator.util.*;
+import net.java.stun4j.client.SimpleAddressDetector;
+import net.java.stun4j.*;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.configuration.event.*;
+import java.text.*;
+
+
+/**
+ * This implementation of the Network Address Manager allows you to
+ * intelligently retrieve the address of your localhost according to preferences
+ * specified in a number of properties like:
+ * <br>
+ * net.java.sip.communicator.STUN_SERVER_ADDRESS - the address of the stun
+ * server to use for NAT traversal
+ * <br>
+ * net.java.sip.communicator.STUN_SERVER_PORT - the port of the stun server
+ * to use for NAT traversal
+ * <br>
+ * java.net.preferIPv6Addresses - a system property specifying weather ipv6
+ * addresses are to be preferred in address resolution (default is false for
+ * backward compatibility)
+ * <br>
+ * net.java.sip.communicator.common.PREFERRED_NETWORK_ADDRESS - the address
+ * that the user would like to use. (If this is a valid address it will be
+ * returned in getLocalhost() calls)
+ * <br>
+ * net.java.sip.communicator.common.PREFERRED_NETWORK_INTERFACE - the network
+ * interface that the user would like to use for fommunication (addresses
+ * belonging to that interface will be prefered when selecting a localhost
+ * address)
+ *
+ * @todo further explain the way the service works. explain address selection
+ * algorithms and priorities.
+ *
+ * @author Emil Ivov
+ * @author Pierre Floury
+ */
+public class NetworkAddressManagerServiceImpl
+ implements NetworkAddressManagerService, VetoableChangeListener
+{
+ private static Logger logger =
+ Logger.getLogger(NetworkAddressManagerServiceImpl.class);
+
+ /**
+ * The name of the property containing the stun server address.
+ */
+ private static final String PROP_STUN_SERVER_ADDRESS
+ = "net.java.sip.communicator.STUN_SERVER_ADDRESS";
+ /**
+ * the port number of the stun server to use for NAT traversal
+ */
+ private static final String PROP_STUN_SERVER_PORT
+ = "net.java.sip.communicator.STUN_SERVER_PORT";
+ /**
+ * a system property specifying weather ipv6
+ * addresses are to be preferred in address resolution (default is false for
+ * backward compatibility)
+ */
+ private static final String PROP_PREF_IPV6_ADDRS
+ = "java.net.preferIPv6Addresses";
+
+ /**
+ * If an application has a preference to only use IPv4 sockets then this
+ * property can be set to true.
+ */
+ private static final String PROP_PREF_IPV4_STACK
+ = "java.net.preferIPv4Stack";
+
+ /**
+ * the address that the user would like to use. (If this is a valid address
+ * it will be returned in getLocalhost() calls)
+ */
+ private static final String PROP_PREFERRED_NET_ADDRESS
+ = "net.java.sip.communicator.common.PREFERRED_NETWORK_ADDRESS";
+
+ /**
+ * the network interface that the user would like to use for fommunication
+ * (addresses belonging to that interface will be prefered when selecting a
+ * localhost address)
+ */
+ private static final String PROP_PREFERRED_NET_IFACE
+ = "net.java.sip.communicator.common.PREFERRED_NETWORK_INTERFACE";
+
+ /** The configuration service to use when retrieving conf property values*/
+ private ConfigurationService configurationService = null;
+
+ /** A stun4j address resolver */
+ private SimpleAddressDetector detector = null;
+
+ /** Specifies whether or not STUN should be used for NAT traversal */
+ private boolean useStun = true;
+ private static final int RANDOM_PORT = 55055;
+ private static final String WINDOWS_AUTO_CONFIGURED_ADDRESS_PREFIX = "169";
+
+ /**
+ * A default constructor.
+ *
+ * @param configurationService the configruation service that this address
+ * manager should use for retrieving configuration properties.
+ */
+ NetworkAddressManagerServiceImpl(ConfigurationService configurationService)
+ {
+ this.configurationService = configurationService;
+ }
+
+ /**
+ * Initializes this network address manager service implementation and
+ * starts all processes/threads associated with this address manager, such
+ * as a stun firewall/nat detector, keep alive threads, binding lifetime
+ * discovery threads and etc. The method may also be used after a call to
+ * stop() as a reinitialization technique.
+ */
+ public void start()
+ {
+ try
+ {
+ logger.logEntry();
+
+ // init stun
+ String stunAddressStr = null;
+ int port = -1;
+ stunAddressStr = configurationService.getString(
+ PROP_STUN_SERVER_ADDRESS);
+ String portStr = configurationService.getString(
+ PROP_STUN_SERVER_PORT);
+
+ //in case the user prefers ipv6 addresses we don't want to use
+ //stun
+ boolean preferIPv6Addresses = Boolean.getBoolean(
+ PROP_PREF_IPV6_ADDRS);
+
+ if (stunAddressStr == null
+ || portStr == null
+ || preferIPv6Addresses)
+ {
+ useStun = false;
+ //user doesn't want stun - bail out
+ return;
+ }
+
+ port = Integer.valueOf(portStr).intValue();
+
+ detector = new SimpleAddressDetector(
+ new StunAddress(stunAddressStr, port));
+
+ if (logger.isDebugEnabled())
+ logger.debug(
+ "Created a STUN Address detector for the following "
+ + "STUN server: "
+ + stunAddressStr + ":" + port);
+
+
+ try
+ {
+ detector.start();
+ logger.debug("STUN server started;");
+ }
+ catch (StunException ex)
+ {
+ logger.error(
+ "Failed to start the STUN Address Detector. " +
+ detector.toString());
+ logger.debug("Disabling stun and continuing bravely!");
+ detector = null;
+ useStun = false;
+ }
+
+ //make sure that someone doesn't set invalid stun address and port
+ configurationService.addVetoableChangeListener(
+ PROP_STUN_SERVER_ADDRESS, this);
+ configurationService.addVetoableChangeListener(
+ PROP_STUN_SERVER_PORT, this);
+
+ //don't register a property listener. reinitialization is supposed
+ //to only happen after a stop(), start() call seq
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Kills all threads/processes lauched by this thread and prepares it for
+ * shutdown. You may use this method as a reinitialization technique (
+ * you'll have to call start afterwards)
+ */
+ public void stop()
+ {
+ try
+ {
+ try{
+ detector.shutDown();
+ }catch (Exception ex){
+ logger.debug("Failed to properly shutdown a stun detector: "
+ +ex.getMessage());
+
+ }
+ detector = null;
+ useStun = false;
+
+ //remove the listeners
+ configurationService.removeVetoableChangeListener(
+ PROP_STUN_SERVER_ADDRESS, this);
+
+ configurationService.removeVetoableChangeListener(
+ PROP_STUN_SERVER_PORT, this);
+
+ }
+ finally
+ {
+ logger.logExit();
+ }
+
+ }
+
+ /**
+ * Returns an InetAddress instance that represents the localhost, and that
+ * a socket can bind upon.
+ *
+ * @return an InetAddress instance representing the local host. The returned
+ * value may also contain the "any" inet address (i.e. 0.0.0.0 or ::0)
+ */
+ public InetAddress getLocalHost()
+ {
+ return getLocalHost(true);
+ }
+
+
+ /**
+ * Returns an InetAddress instance that represents the localhost, and that
+ * a socket can bind upon.
+ *
+ * @param anyAddressIsAccepted are (0.0.0.0 / ::0) addresses accepted as a
+ * return value.
+ * @return the address that was detected the address of the localhost.
+ */
+ public InetAddress getLocalHost(boolean anyAddressIsAccepted)
+ {
+ try
+ {
+ logger.logEntry();
+ InetAddress localHost = null;
+ InetAddress mappedAddress = null;
+ InetAddress stunConfirmedAddress = null;
+ InetAddress linkLocalAddress = null;
+ InetAddress publicAddress = null;
+ String selectedInterface = null;
+
+ //let's check whether the user has any preferences concerning addrs
+ String preferredAddr =
+ configurationService.getString(PROP_PREFERRED_NET_ADDRESS);
+ String preferredIface =
+ configurationService.getString(PROP_PREFERRED_NET_IFACE);
+
+ boolean preferIPv4Stack = Boolean.getBoolean(PROP_PREF_IPV4_STACK);
+ boolean preferIPv6Addrs = Boolean.getBoolean(PROP_PREF_IPV6_ADDRS);
+
+ try
+ {
+ //check whether we have a public address that matches one of
+ //the local interfaces if not - return the first one that
+ //is not the loopback
+
+ //retrieve and store a STUN binding if possible
+ if (useStun)
+ {
+ StunAddress stunMappedAddress =
+ queryStunServer(RANDOM_PORT);
+
+ mappedAddress = (stunMappedAddress == null)
+ ? null
+ : stunMappedAddress.getSocketAddress().getAddress();
+ }
+
+ Enumeration localIfaces =
+ NetworkInterface.getNetworkInterfaces();
+
+ //do a loop over all addresses of all interfaces and return
+ //the first that we judge correct.
+
+ //interfaces loop
+ interfaces_loop:
+ while (localIfaces.hasMoreElements())
+ {
+ NetworkInterface iFace =
+ (NetworkInterface) localIfaces.nextElement();
+
+ Enumeration addresses = iFace.getInetAddresses();
+
+ //addresses loop
+ addresses_loop:
+ while (addresses.hasMoreElements()) {
+ InetAddress address =
+ (InetAddress) addresses.nextElement();
+ //ignore link local addresses
+ if (address.isAnyLocalAddress()
+ || address.isLinkLocalAddress()
+ || address.isLoopbackAddress()
+ || isWindowsAutoConfiguredIPv4Address(address))
+ {
+ //address is phony - go on to the next one
+ continue addresses_loop;
+ }
+ //see whether this is the address used in STUN communic.
+ if (mappedAddress != null
+ && mappedAddress.equals(address)) {
+ if (logger.isDebugEnabled())
+ logger.debug("Returninng localhost: Mapped "
+ + "address = Public address = "
+ + address);
+ //the addr matches the one seen by the STUN server
+ //no doubt that it's a working public
+ //address.
+
+ stunConfirmedAddress = address;
+ }
+ //link local addr
+ else if (isLinkLocalIPv4Address(address))
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found Linklocal ipv4 address "
+ + address);
+ linkLocalAddress = address;
+ }
+ //publicly routable addr
+ else {
+ if (logger.isDebugEnabled())
+ logger.debug("Found a public address "
+ + address);
+
+ //now befo we store this address, make sure we don't
+ //already have one that suits us better and bail out
+ //if this is the case
+
+ if (//we already have the address prefferred by user
+ ( publicAddress != null
+ && preferredAddr!= null
+ && preferredAddr.equals(publicAddress.
+ getHostAddress()))
+ //we already have an address on an iface
+ //preferred by the user
+ ||(publicAddress != null
+ && selectedInterface != null
+ && preferredIface != null
+ && preferredIface.equals(selectedInterface))
+ //in case we have an ipv4 addr and don't
+ //want to change it for an ipv6
+ ||(publicAddress != null
+ && publicAddress instanceof Inet4Address
+ && address instanceof Inet6Address
+ && preferIPv4Stack)
+ //in case we have an ipv6 addr and don't
+ //want to change it for an ipv4
+ ||(publicAddress != null
+ && publicAddress instanceof Inet6Address
+ && address instanceof Inet4Address
+ && !preferIPv4Stack)
+ )
+ {
+ continue;
+ }
+ publicAddress = address;
+ selectedInterface = iFace.getDisplayName();
+ }
+ }//addresses loop
+ }//interfaces loop
+
+ //if we have an address confirmed by STUN msg exchanges - we'll
+ //return it unless the user had really insisted on IPv6 addresses.
+ if(stunConfirmedAddress != null
+ && ! preferIPv6Addrs){
+ logger.debug("Returning stun confirmed address");
+ return stunConfirmedAddress;
+ }
+ //return the address that was selected during the loop above.
+ if (publicAddress != null) {
+ logger.debug("Returning public address");
+ return publicAddress;
+ }
+ if (linkLocalAddress != null) {
+ logger.debug("Returning link local address");
+ return linkLocalAddress;
+ }
+ if (anyAddressIsAccepted)
+ localHost = new InetSocketAddress(RANDOM_PORT).getAddress();
+ else
+ localHost = InetAddress.getLocalHost();
+ }
+ catch (Exception ex) {
+ logger.error("Failed to determine the localhost address, "
+ +"returning the any address (0.0.0.0/::0)", ex);
+ //get the address part of an InetSocketAddress for a random port.
+ localHost = new InetSocketAddress(RANDOM_PORT).getAddress();
+ }
+ if (logger.isDebugEnabled())
+ logger.debug("Returning localhost address=" + localHost);
+ return localHost;
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * The method queries a Stun server for a binding for the specified port.
+ * @param port the port to resolve (the stun message gets sent trhough that
+ * port)
+ * @return StunAddress the address returned by the stun server or null
+ * if an error occurred or no address was returned
+ */
+ private StunAddress queryStunServer(int port)
+ {
+
+ try{
+ logger.logEntry();
+ StunAddress mappedAddress = null;
+ if (detector != null && useStun) {
+ try {
+ mappedAddress = detector.getMappingFor(port);
+ if (logger.isDebugEnabled())
+ logger.debug("For port:"
+ + port + "a Stun server returned the "
+ +"following mapping [" + mappedAddress);
+ }
+ catch (StunException ex) {
+ logger.error(
+ "Failed to retrive mapped address port:" +port, ex);
+ mappedAddress = null;
+ }
+ }
+ return mappedAddress;
+ }
+ finally{
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Determines whether the address is the result of windows auto configuration.
+ * (i.e. One that is in the 169.254.0.0 network)
+ * @param add the address to inspect
+ * @return true if the address is autoconfigured by windows, false otherwise.
+ */
+ private static boolean isWindowsAutoConfiguredIPv4Address(InetAddress add)
+ {
+ return (add.getAddress()[0] & 0xFF) == 169
+ && (add.getAddress()[1] & 0xFF) == 254;
+ }
+
+ /**
+ * Determines whether the address is an IPv4 link local address. IPv4 link
+ * local addresses are those in the following networks:
+ *
+ * 10.0.0.0 to 10.255.255.255
+ * 172.16.0.0 to 172.31.255.255
+ * 192.168.0.0 to 192.168.255.255
+ *
+ * @param add the address to inspect
+ * @return true if add is a link local ipv4 address and false if not.
+ */
+ private static boolean isLinkLocalIPv4Address(InetAddress add)
+ {
+ if(add instanceof Inet4Address)
+ {
+ byte address[] = add.getAddress();
+ if ( (address[0] & 0xFF) == 10)
+ return true;
+ if ( (address[0] & 0xFF) == 172
+ && (address[1] & 0xFF) >= 16 && address[1] <= 31)
+ return true;
+ if ( (address[0] & 0xFF) == 192
+ && (address[1] & 0xFF) == 168)
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Tries to obtain a mapped/public address for the specified port (possibly
+ * by executing a STUN query).
+ *
+ * @param port the port whose mapping we are interested in.
+ * @return a public address corresponding to the specified port or null
+ * if all attempts to retrieve such an address have failed.
+ */
+ public InetSocketAddress getPublicAddressFor(int port)
+ {
+ try {
+ logger.logEntry();
+ if (!useStun) {
+ logger.debug(
+ "Stun is disabled, skipping mapped address recovery.");
+ return new InetSocketAddress(getLocalHost(), port);
+ }
+ StunAddress mappedAddress = queryStunServer(port);
+ InetSocketAddress result = null;
+ if (mappedAddress != null)
+ result = mappedAddress.getSocketAddress();
+ else {
+ //Apparently STUN failed. Let's try to temporarily disble it
+ //and use algorithms in getLocalHost(). ... We should probably
+ //eveng think about completely disabling stun, and not only
+ //temporarily.
+ //Bug report - John J. Barton - IBM
+ InetAddress localHost = getLocalHost(false);
+ result = new InetSocketAddress(localHost, port);
+ }
+ if (logger.isDebugEnabled())
+ logger.debug("Returning mapping for port:"
+ + port +" as follows: " + result);
+ return result;
+ }
+ finally {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * This method gets called when a bound property is changed.
+ * @param evt A PropertyChangeEvent object describing the event source
+ * and the property that has changed.
+ */
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ //there's no point in implementing this method as we have no way of
+ //knowing whether the current property change event is the only event
+ //we're going to get or whether another one is going to follow..
+
+ //in the case of a STUN_SERVER_ADDRESS property change for example
+ //there's no way of knowing whether a STUN_SERVER_PORT property change
+ //will follow or not.
+
+ //Reinitializaion will therefore only happen if the reinitialize()
+ //method is called.
+ }
+
+ /**
+ * This method gets called when a property we're interested in is about to
+ * change. In case we don't like the new value we throw a
+ * PropertyVetoException to prevent the actual change from happening.
+ *
+ * @param evt a <code>PropertyChangeEvent</code> object describing the
+ * event source and the property that will change.
+ * @exception PropertyVetoException if we don't want the change to happen.
+ */
+ public void vetoableChange(PropertyChangeEvent evt) throws
+ PropertyVetoException
+ {
+ if (evt.getPropertyName().equals(PROP_STUN_SERVER_ADDRESS))
+ {
+ //make sure that we have a valid fqdn or ip address.
+
+ //null or empty port is ok since it implies turning STUN off.
+ if (evt.getNewValue() == null)
+ return;
+
+ String host = evt.getNewValue().toString();
+ if (host.trim().length() == 0)
+ return;
+
+ boolean ipv6Expected = false;
+ if (host.charAt(0) == '[')
+ {
+ // This is supposed to be an IPv6 litteral
+ if (host.length() > 2 &&
+ host.charAt(host.length() - 1) == ']')
+ {
+ host = host.substring(1, host.length() - 1);
+ ipv6Expected = true;
+ }
+ else
+ {
+ // This was supposed to be a IPv6 address, but it's not!
+ throw new PropertyVetoException(
+ "Invalid address string" + host, evt);
+ }
+ }
+
+ for(int i = 0; i < host.length(); i++)
+ {
+ char c = host.charAt(i);
+ if( Character.isLetterOrDigit(c))
+ continue;
+
+ if( (c != '.' && c!= ':')
+ ||( c == '.' && ipv6Expected)
+ ||( c == ':' && !ipv6Expected))
+ throw new PropertyVetoException(
+ host + " is not a valid address nor host name",
+ evt);
+ }
+
+ }//is prop_stun_server_address
+ else if (evt.getPropertyName().equals(PROP_STUN_SERVER_PORT)){
+
+ //null or empty port is ok since it implies turning STUN off.
+ if (evt.getNewValue() == null)
+ return;
+
+ String port = evt.getNewValue().toString();
+ if (port.trim().length() == 0)
+ return;
+
+ try
+ {
+ Integer.valueOf(evt.getNewValue().toString());
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new PropertyVetoException(
+ port + " is not a valid port! " + ex.getMessage(), evt);
+ }
+
+
+ }
+
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/StunClient.java b/src/net/java/sip/communicator/impl/netaddr/StunClient.java
new file mode 100644
index 0000000..a89cc95
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/StunClient.java
@@ -0,0 +1,291 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import java.net.*;
+
+import net.java.stun4j.*;
+import net.java.stun4j.attribute.*;
+import net.java.stun4j.message.*;
+import net.java.stun4j.stack.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * <p>
+ * This class implements the STUN Discovery Process as described by section 10.1
+ * of rfc 3489.
+ * </p><p>
+ * The flow makes use of three tests. In test I, the client sends a
+ * STUN Binding Request to a server, without any flags set in the
+ * CHANGE-REQUEST attribute, and without the RESPONSE-ADDRESS attribute.
+ * This causes the server to send the response back to the address and
+ * port that the request came from. In test II, the client sends a
+ * Binding Request with both the "change IP" and "change port" flags
+ * from the CHANGE-REQUEST attribute set. In test III, the client sends
+ * a Binding Request with only the "change port" flag set.
+ * </p><p>
+ * The client begins by initiating test I. If this test yields no
+ * response, the client knows right away that it is not capable of UDP
+ * connectivity. If the test produces a response, the client examines
+ * the MAPPED-ADDRESS attribute. If this address and port are the same
+ * as the local IP address and port of the socket used to send the
+ * request, the client knows that it is not natted. It executes test
+ * II.
+ * </p><p>
+ * If a response is received, the client knows that it has open access
+ * to the Internet (or, at least, its behind a firewall that behaves
+ * like a full-cone NAT, but without the translation). If no response
+ * is received, the client knows its behind a symmetric UDP firewall.
+ * </p><p>
+ * In the event that the IP address and port of the socket did not match
+ * the MAPPED-ADDRESS attribute in the response to test I, the client
+ * knows that it is behind a NAT. It performs test II. If a response
+ * is received, the client knows that it is behind a full-cone NAT. If
+ * no response is received, it performs test I again, but this time,
+ * does so to the address and port from the CHANGED-ADDRESS attribute
+ * from the response to test I. If the IP address and port returned in
+ * the MAPPED-ADDRESS attribute are not the same as the ones from the
+ * first test I, the client knows its behind a symmetric NAT. If the
+ * address and port are the same, the client is either behind a
+ * restricted or port restricted NAT. To make a determination about
+ * which one it is behind, the client initiates test III. If a response
+ * is received, its behind a restricted NAT, and if no response is
+ * received, its behind a port restricted NAT.
+ * </p><p>
+ * This procedure yields substantial information about the operating
+ * condition of the client application. In the event of multiple NATs
+ * between the client and the Internet, the type that is discovered will
+ * be the type of the most restrictive NAT between the client and the
+ * Internet. The types of NAT, in order of restrictiveness, from most
+ * to least, are symmetric, port restricted cone, restricted cone, and
+ * full cone.
+ * </p><p>
+ * Typically, a client will re-do this discovery process periodically to
+ * detect changes, or look for inconsistent results. It is important to
+ * note that when the discovery process is redone, it should not
+ * generally be done from the same local address and port used in the
+ * previous discovery process. If the same local address and port are
+ * reused, bindings from the previous test may still be in existence,
+ * and these will invalidate the results of the test. Using a different
+ * local address and port for subsequent tests resolves this problem.
+ * An alternative is to wait sufficiently long to be confident that the
+ * old bindings have expired (half an hour should more than suffice).
+ * </p><p>
+ * <p>Organisation: <p> Louis Pasteur University, Strasbourg, France</p>
+ * <p>Network Research Team (http://www-r2.u-strasbg.fr)</p></p>
+ * @author Emil Ivov
+ * @version 0.1
+ */
+
+public class StunClient
+{
+ private static final Logger logger =
+ Logger.getLogger(StunClient.class);
+ /**
+ * Indicates whether the underlying stack has been initialized and started
+ * and that the discoverer is operational.
+ */
+ private boolean started = false;
+
+ /**
+ * The stack to use for STUN communication.
+ */
+ private StunStack stunStack = null;
+
+ /**
+ * The provider to send our messages through
+ */
+ private StunProvider stunProvider = null;
+
+ /**
+ * The point where we'll be listening.
+ */
+ private NetAccessPointDescriptor apDescriptor = null;
+
+ /**
+ * The address of the stun server
+ */
+ private StunAddress serverAddress = null;
+
+ /**
+ * A utility used to flatten the multithreaded architecture of the Stack
+ * and execute the discovery process in a synchronized manner
+ */
+ private BlockingRequestSender requestSender = null;
+
+ /**
+ * Creates a StunAddressDiscoverer. In order to use it one must start the
+ * discoverer.
+ * @param localAddress the address where the stach should bind.
+ */
+ public StunClient(StunAddress localAddress)
+ {
+ apDescriptor = new NetAccessPointDescriptor(localAddress);
+ }
+
+ /**
+ * Creates a StunAddressDiscoverer. In order to use it one must start the
+ * discoverer.
+ * @param apDescriptor the address where the stach should bind.
+ * @param serverAddress the address of the server to interrogate.
+ */
+ public StunClient(NetAccessPointDescriptor apDescriptor,
+ StunAddress serverAddress)
+ {
+ this.apDescriptor = apDescriptor;
+ this.serverAddress = serverAddress;
+
+ }
+
+ /**
+ * Shuts down the underlying stack and prepares the object for garbage
+ * collection.
+ */
+ public void shutDown()
+ {
+ try
+ {
+ stunStack.removeNetAccessPoint(apDescriptor);
+ }
+ catch (StunException ex)
+ {
+ logger.warn("Failed to remove NetAP: "+apDescriptor.toString(), ex);
+ }
+ stunStack = null;
+ stunProvider = null;
+ apDescriptor = null;
+ requestSender = null;
+
+ this.started = false;
+
+ }
+
+ /**
+ * Puts the discoverer into an operational state.
+ * @throws StunException if we fail to bind or some other error occurs.
+ */
+ public void start() throws StunException
+ {
+ stunStack = StunStack.getInstance();
+ stunStack.start();
+
+ stunStack.installNetAccessPoint(apDescriptor);
+
+ stunProvider = stunStack.getProvider();
+
+ requestSender = new BlockingRequestSender(stunProvider, apDescriptor);
+
+ started = true;
+ }
+
+ /**
+ * Sends a binding request to the specified server address. Both change IP
+ * and change port flags are set to false.
+ * @param serverAddress the address where to send the bindingRequest.
+ * @return The returned message encapsulating event or null if no message
+ * was received.
+ * @throws StunException if an exception occurs while sending the messge
+ */
+ public StunMessageEvent doStunTestI(StunAddress serverAddress) throws
+ StunException
+ {
+ Request request = MessageFactory.createBindingRequest();
+
+ ChangeRequestAttribute changeRequest =
+ (ChangeRequestAttribute) request.getAttribute(Attribute.
+ CHANGE_REQUEST);
+ changeRequest.setChangeIpFlag(false);
+ changeRequest.setChangePortFlag(false);
+ StunMessageEvent evt =
+ requestSender.sendRequestAndWaitForResponse(request, serverAddress);
+ if (evt != null)
+ System.out.println("TEST I res=" + evt.getRemoteAddress().toString()
+ + " - " + evt.getRemoteAddress().getHostName());
+ else
+ System.out.println("NO RESPONSE received to TEST I.");
+ return evt;
+ }
+
+ /**
+ * Sends a binding request to the specified server address with both change
+ * IP and change port flags are set to true.
+ * @param serverAddress the address where to send the bindingRequest.
+ * @return The returned message encapsulating event or null if no message
+ * was received.
+ * @throws StunException if an exception occurs while sending the messge
+ */
+ public StunMessageEvent doStunTestII(StunAddress serverAddress) throws
+ StunException
+ {
+ Request request = MessageFactory.createBindingRequest();
+
+ ChangeRequestAttribute changeRequest =
+ (ChangeRequestAttribute) request.getAttribute(Attribute.
+ CHANGE_REQUEST);
+ changeRequest.setChangeIpFlag(true);
+ changeRequest.setChangePortFlag(true);
+
+ StunMessageEvent evt =
+ requestSender.sendRequestAndWaitForResponse(request, serverAddress);
+ if (evt != null)
+ System.out.println("Test II res=" + evt.getRemoteAddress().toString()
+ + " - " + evt.getRemoteAddress().getHostName());
+ else
+ System.out.println("NO RESPONSE received to Test II.");
+
+ return evt;
+ }
+
+ /**
+ * Sends a binding request to the specified server address with only change
+ * port flag set to true and change IP flag - to false.
+ * @param serverAddress the address where to send the bindingRequest.
+ * @return The returned message encapsulating event or null if no message
+ * was received.
+ * @throws StunException if an exception occurs while sending the messge
+ */
+ public StunMessageEvent doStunTestIII(StunAddress serverAddress) throws
+ StunException
+ {
+ Request request = MessageFactory.createBindingRequest();
+
+ ChangeRequestAttribute changeRequest = (ChangeRequestAttribute) request.
+ getAttribute(Attribute.CHANGE_REQUEST);
+ changeRequest.setChangeIpFlag(false);
+ changeRequest.setChangePortFlag(true);
+
+ StunMessageEvent evt =
+ requestSender.sendRequestAndWaitForResponse(request, serverAddress);
+ if (evt != null)
+ System.out.println("Test III res=" +
+ evt.getRemoteAddress().toString()
+ + " - " + evt.getRemoteAddress().getHostName());
+ else
+ System.out.println("NO RESPONSE received to Test III.");
+
+ return evt;
+ }
+
+ /**
+ * Makes shure the discoverer is operational and throws an
+ * StunException.ILLEGAL_STATE if that is not the case.
+ * @throws StunException ILLEGAL_STATE if the discoverer is not operational.
+ */
+ private void checkStarted() throws StunException
+ {
+ if (!started)
+ throw new StunException(StunException.ILLEGAL_STATE,
+ "The Discoverer must be started before "
+ + "launching the discovery process!");
+ }
+}
+/**
+ * Sample run results.
+ *
+ * TEST I res=/69.0.209.22:3478 - stun01bak.sipphone.com
+ * mapped address is=193.108.24.226./193.108.24.226:5678, name=193.108.24.226.
+ * backup server address is=69.0.208.27./69.0.208.27:3478, name=69.0.208.27.
+ * NO RESPONSE received to Test II.
+ * TEST I res=/69.0.208.27:3478 - stun01.sipphone.com
+ * NO RESPONSE received to Test III.
+ * The detected network configuration is: Port Restricted Cone NAT
+ * Your mapped public address is: 193.108.24.226./193.
+ */
diff --git a/src/net/java/sip/communicator/impl/netaddr/StunDiscoveryReport.java b/src/net/java/sip/communicator/impl/netaddr/StunDiscoveryReport.java
new file mode 100644
index 0000000..af34bdc
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/StunDiscoveryReport.java
@@ -0,0 +1,143 @@
+package net.java.sip.communicator.impl.netaddr;
+
+import net.java.stun4j.StunAddress;
+
+/**
+ * The class is used to deliver results from a STUN Discovery Process. It
+ * contains information about the NAT Server (or firewall )this client is behind,
+ * and a mapped address value (if discovered)
+ *
+ *
+ * <p>Organisation: <p> Louis Pasteur University, Strasbourg, France</p>
+ * <p>Network Research Team (http://www-r2.u-strasbg.fr)</p></p>
+ * @author Emil Ivov
+ * @version 0.1
+ */
+
+public class StunDiscoveryReport
+{
+ /**
+ * Indicates that NAT detection has failed or not yet initiated.
+ */
+ public static final String UNKNOWN = "Unknown Network Configuration";
+
+ /**
+ * Means, there's no NAT or firewall.
+ */
+ public static final String OPEN_INTERNET = "Open Internet Configuration";
+
+ /**
+ * Indicates that UDP communication is not possible.
+ */
+ public static final String UDP_BLOCKING_FIREWALL = "UDP Blocking Firewall";
+
+ /**
+ * Means we are behind a symmetric udp firewall.
+ */
+ public static final String SYMMETRIC_UDP_FIREWALL= "Symmetric UDP Firewall";
+
+ /**
+ * NAT type is full cone.
+ */
+ public static final String FULL_CONE_NAT = "Full Cone NAT";
+
+ /**
+ * We are behind a symmetric nat.
+ */
+ public static final String SYMMETRIC_NAT = "Symmetric NAT";
+
+ /**
+ * NAT type is Restricted Cone.
+ */
+ public static final String RESTRICTED_CONE_NAT = "Restricted Cone NAT";
+
+ /**
+ * NAT type is port restricted cone.
+ */
+ public static final String PORT_RESTRICTED_CONE_NAT= "Port Restricted Cone NAT";
+
+ private String natType = UNKNOWN;
+
+
+ private StunAddress publicAddress = null;
+
+ /**
+ * Creates a discovery report with natType = UNKNOWN and a null public
+ * address.
+ */
+ StunDiscoveryReport()
+ {
+ }
+
+ /**
+ * Returns the type of the NAT described in the report.
+ * @return the type of the NAT that this report is about.
+ */
+ public String getNatType()
+ {
+ return natType;
+ }
+
+ /**
+ * Sets the type of the NAT indicated by the report.
+ * @param natType the type of the NAT.
+ */
+ void setNatType(String natType)
+ {
+ this.natType = natType;
+ }
+
+ /**
+ * Returns the public addressed discovered by a discovery process.
+ * @return an Inetner address for public use.
+ */
+ public StunAddress getPublicAddress()
+ {
+ return publicAddress;
+ }
+
+ /**
+ * Sets a public address.
+ * @param stunAddress An address that's accesible from everywhere.
+ */
+ void setPublicAddress(StunAddress stunAddress)
+ {
+ this.publicAddress = stunAddress;
+ }
+
+
+ /**
+ * Compares this object with obj. Two reports are considered equal if and
+ * only if both have the same nat type and their public addresses are
+ * equal or are both null.
+ * @param obj the object to compare against.
+ * @return true if the two objects are equal and false otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(obj == null
+ || !(obj instanceof StunDiscoveryReport))
+ return false;
+
+ if(obj == this)
+ return true;
+
+ StunDiscoveryReport target = (StunDiscoveryReport)obj;
+
+ return ( target.getNatType() == getNatType()
+ && ( getPublicAddress() == null && target.getPublicAddress() == null
+ || target.getPublicAddress().equals(getPublicAddress())));
+ }
+
+ /**
+ * Returns a readable representation of the report.
+ * @return a readable representation of the report.
+ */
+ public String toString()
+ {
+ return "The detected network configuration is: " + getNatType() + "\n"
+ + "Your mapped public address is: " + getPublicAddress();
+ }
+
+
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf b/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf
new file mode 100644
index 0000000..e8528f9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf
@@ -0,0 +1,14 @@
+Bundle-Activator: net.java.sip.communicator.impl.netaddr.Activator
+Bundle-Name: Network address managment service
+Bundle-Description: A bundle that provide a gesture of the ip addresses. prospere est le toi du pain d'epice
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: net.java.stun4j,
+ net.java.stun4j.client,
+ net.java.stun4j.StunAddress,
+ net.java.stun4j.StunException,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.configuration.event,
+ net.java.sip.communicator.util,
+ org.osgi.framework,
+Export-Package: net.java.sip.communicator.service.netaddr,
diff --git a/src/net/java/sip/communicator/impl/netaddr/res/netaddr.manifest.mf b/src/net/java/sip/communicator/impl/netaddr/res/netaddr.manifest.mf
new file mode 100644
index 0000000..71dd4cb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/res/netaddr.manifest.mf
@@ -0,0 +1,7 @@
+Bundle-Name: Network address managment service
+Bundle-Activator: net.java.sip.communicator.impl.netaddr.Activator
+Export-Package: net.java.sip.communicator.service.netaddr;
+Import-Package: net.java.sip.communicator.service.configuration,net.java.sip.communicator.service.configuration.event, net.java.sip.communicator.util,net.java.stun4j, net.java.sip.communicator.util;junit;junit.framework, junit.swingui;junit.textui;junit.awtui, junit.extensions;org.osgi.framework
+Bundle-Description: A bundle that provide a gesture of the ip addresses. prospere est le toi du pain d'epice
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1 \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/Activator.java b/src/net/java/sip/communicator/impl/protocol/sip/Activator.java
new file mode 100644
index 0000000..ea9fae9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/Activator.java
@@ -0,0 +1,44 @@
+package net.java.sip.communicator.impl.protocol.sip;
+
+import org.osgi.framework.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Activates the SIP package
+ * @author Emil Ivov
+ */
+public class Activator
+ implements BundleActivator
+{
+ private Logger logger = Logger.getLogger(Activator.class.getName());
+
+ /**
+ * Called when this bundle is started so the Framework can perform the
+ * bundle-specific activities necessary to start this bundle.
+ *
+ * @param context The execution context of the bundle being started.
+ * @throws Exception If this method throws an exception, this bundle is
+ * marked as stopped and the Framework will remove this bundle's
+ * listeners, unregister all services registered by this bundle, and
+ * release all services used by this bundle.
+ */
+ public void start(BundleContext context) throws Exception
+ {
+ logger.debug("Started.");
+ }
+
+ /**
+ * Called when this bundle is stopped so the Framework can perform the
+ * bundle-specific activities necessary to stop the bundle.
+ *
+ * @param context The execution context of the bundle being stopped.
+ * @throws Exception If this method throws an exception, the bundle is
+ * still marked as stopped, and the Framework will remove the bundle's
+ * listeners, unregister all services registered by the bundle, and
+ * release all services used by the bundle.
+ */
+ public void stop(BundleContext context) throws Exception
+ {
+ logger.debug("Stopped.");
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipProtocolProviderServiceImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/SipProtocolProviderServiceImpl.java
new file mode 100644
index 0000000..0a859bf
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipProtocolProviderServiceImpl.java
@@ -0,0 +1,230 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public class SipProtocolProviderServiceImpl
+ implements ProtocolProviderService
+{
+ public static final String SIP_PROTOCOL_NAME = "SIP";
+ /**
+ * Returns the short name of the protocol that the implementation of this
+ * provider is based upon, or in other words - SIP.
+ *
+ * @return a String containing the name of our protocol - SIP.
+ */
+ public String getProtocolName()
+ {
+ return SIP_PROTOCOL_NAME;
+ }
+
+ /**
+ * Registers the specified listener with this provider so that it would
+ * receive notifications on changes of its state or other properties such
+ * as its local address and display name.
+ *
+ * @param listener the listener to register.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public void addProviderChangeListener(ProviderChangeListener listener)
+ {
+ }
+
+ /**
+ * Requests the provider to enter into a status corresponding to the
+ * specified paramters.
+ *
+ * @param status the PresenceStatus as returned by
+ * getRequestableStatusSet
+ * @param statusMessage the message that should be set as the reason to
+ * enter that status
+ * @throws IllegalArgumentException if the status requested is not a
+ * valid PresenceStatus supported by this provider.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public void enterStatus(PresenceStatus status, String statusMessage) throws
+ IllegalArgumentException
+ {
+ }
+
+ /**
+ * Returns the protocol specific contact instance representing the local
+ * user.
+ *
+ * @return the Contact (address, phone number, or uin) that the Provider
+ * implementation is communicating on behalf of.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public Contact getLocalContact()
+ {
+ return null;
+ }
+
+ /**
+ * Many communications protocols have well known logos that users are
+ * familiar with.
+ *
+ * @return byte[] a 32x32 protocol logo or representative image.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public byte[] getProviderImage()
+ {
+ return null;
+ }
+
+ /**
+ * Returns a String containing a human readable string representation of
+ * the provider.
+ *
+ * @return a String representation of this provider.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public String getProviderName()
+ {
+ return "";
+ }
+
+ /**
+ * Returns a string representation of the registration service that is
+ * used by this provider or null if none is used.
+ *
+ * @return a string representing (the address of) the service being used.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public String getRegistrationServer()
+ {
+ return "";
+ }
+
+ /**
+ * Returns the set of PresenceStatus objects that a user of this service
+ * may request the provider to enter.
+ *
+ * @return Iterator a PresenceStatus array containing "enterable" status
+ * instances.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public Iterator getRequestableStatusSet()
+ {
+ return null;
+ }
+
+ /**
+ * Returns a PresenceStatus instance representing the state this provider
+ * is currently in.
+ *
+ * @return PresenceStatus
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public PresenceStatus getStatus()
+ {
+ return null;
+ }
+
+ /**
+ * Returns an array containing all operation sets supported by the
+ * current implementation.
+ *
+ * @return an array of OperationSet-s supported by this protocol
+ * provider implementation.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public OperationSet[] getSupportedOperationSets()
+ {
+ return null;
+ }
+
+ /**
+ * Initialized the service implementation, and puts it in a sate where it
+ * could interoperate with other services.
+ *
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public void initialize()
+ {
+ }
+
+ /**
+ * Returns true if the provider service implementation is initialized and
+ * ready for use by other services, and false otherwise.
+ *
+ * @return boolean
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public boolean isInitialized()
+ {
+ return false;
+ }
+
+ /**
+ * Removes the specified listener.
+ *
+ * @param listener the listener to remove.
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public void removeProviderChangeListener(ProviderChangeListener listener)
+ {
+ }
+
+ /**
+ * Allows the user interface to plugin an object that would handle
+ * incoming authentication challenges.
+ *
+ * @param authority SecurityAuthority
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public void setSecurityAuthority(SecurityAuthority authority)
+ {
+ }
+
+ /**
+ * Makes the service implementation close all open sockets and release
+ * any resources that it might have taken and prepare for
+ * shutdown/garbage collection.
+ *
+ * @todo Implement this
+ * net.java.sip.communicator.service.protocol.ProtocolProviderService
+ * method
+ */
+ public void shutdown()
+ {
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
new file mode 100644
index 0000000..85893e5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
@@ -0,0 +1,7 @@
+Bundle-Activator: net.java.sip.communicator.impl.protocol.sip.Activator
+Bundle-Name: SIP Communicator SIP Protocol Provider
+Bundle-Description: A bundle that implements the Protocol Provider package over SIP.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: net.java.sip.communicator.util,
+Export-Package: net.java.sip.communicator.protocol,
diff --git a/src/net/java/sip/communicator/impl/resources/Activator.java b/src/net/java/sip/communicator/impl/resources/Activator.java
new file mode 100644
index 0000000..152811b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/resources/Activator.java
@@ -0,0 +1,14 @@
+package net.java.sip.communicator.impl.resources;
+
+import org.ungoverned.gravity.servicebinder.GenericActivator;
+
+/**
+ * Invoke "Service Binder" to parse the service XML and register
+ * all services.
+ *
+ * @author Emil Ivov
+ * @author Alexander Pelov
+ */
+public class Activator extends GenericActivator {
+
+}
diff --git a/src/net/java/sip/communicator/impl/resources/FileAccessServiceImpl.java b/src/net/java/sip/communicator/impl/resources/FileAccessServiceImpl.java
new file mode 100644
index 0000000..1dc551a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/resources/FileAccessServiceImpl.java
@@ -0,0 +1,267 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.resources;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.java.sip.communicator.service.configuration.ConfigurationService;
+import net.java.sip.communicator.service.resources.FileAccessService;
+import net.java.sip.communicator.util.Assert;
+import net.java.sip.communicator.util.Logger;
+
+/**
+ * Default FileAccessService implementation.
+ *
+ * @author Alexander Pelov
+ */
+public class FileAccessServiceImpl implements FileAccessService {
+
+ /**
+ * The logger for this class.
+ */
+ private static Logger logger = Logger
+ .getLogger(FileAccessServiceImpl.class);
+
+ /**
+ * The file prefix for all temp files.
+ */
+ public static final String TEMP_FILE_PREFIX = "SIPCOMM";
+
+ /**
+ * The file suffix for all temp files.
+ */
+ public static final String TEMP_FILE_SUFFIX = "TEMP";
+
+ /**
+ * List of available configuration services.
+ */
+ private ConfigurationService configurationService = null;
+
+ /**
+ * An synchronization object.
+ *
+ * A lock should be obtained whenever the configuration service is
+ * accessed.
+ */
+ private Object syncRoot = new Object();
+
+ /**
+ * Set the configuration service.
+ *
+ * @param configurationService
+ */
+ public void setConfigurationService(
+ ConfigurationService configurationService)
+ {
+ synchronized(this.syncRoot) {
+ this.configurationService = configurationService;
+ logger.debug("New configuration service registered.");
+ }
+ }
+
+ /**
+ * Remove a configuration service.
+ *
+ * @param configurationService
+ */
+ public void unsetConfigurationService(
+ ConfigurationService configurationService)
+ {
+ synchronized(this.syncRoot) {
+ if(this.configurationService == configurationService) {
+ this.configurationService = null;
+ logger.debug("Configuration service unregistered.");
+ }
+ }
+ }
+
+ public File getTemporaryFile() throws IOException {
+ File retVal = null;
+
+ try {
+ logger.logEntry();
+
+ retVal = TempFileManager.createTempFile(TEMP_FILE_PREFIX,
+ TEMP_FILE_SUFFIX);
+ } finally {
+ logger.logExit();
+ }
+
+ return retVal;
+ }
+
+ public File getTemporaryDirectory() throws IOException {
+ File file = getTemporaryFile();
+
+ if(!file.delete()) {
+ throw new IOException("Could not create temporary directory, " +
+ "because: could not delete temporary file.");
+ }
+ if(!file.mkdirs()) {
+ throw new IOException("Could not create temporary directory");
+ }
+
+ return file;
+ }
+
+ /**
+ * @throws IllegalStateException
+ * Thrown if the configuration service is not set
+ */
+ public File getPrivatePersistentFile(String fileName) throws Exception {
+ Assert.assertNonNull(fileName, "Parameter fileName should be non-null");
+
+ File file = null;
+
+ try {
+ logger.logEntry();
+
+
+ String fullPath = getFullPath(fileName);
+ file = this.accessibleFile(fullPath, fileName);
+
+ if(file == null) {
+ throw new SecurityException("Insufficient rights to access " +
+ "this file in current user's home directory: "
+ + file.getAbsolutePath());
+ }
+ } finally {
+ logger.logExit();
+ }
+
+ return file;
+ }
+
+ public File getPrivatePersistentDirectory(String dirName)
+ throws Exception
+ {
+ Assert.assertNonNull(dirName, "Parameter dirName should be non-null");
+
+ String fullPath = getFullPath(dirName);
+ File dir = new File(fullPath, dirName);
+
+ if(dir.exists()) {
+ if(!dir.isDirectory()) {
+ throw new RuntimeException("Could not create directory " +
+ "because: A file exists with this name:" +
+ dir.getAbsolutePath());
+ }
+ } else {
+ if(!dir.mkdirs()) {
+ throw new IOException("Could not create directory");
+ }
+ }
+
+ return dir;
+ }
+
+ public File getPrivatePersistentDirectory(String[] dirNames) throws Exception {
+ Assert.assertNonNull(dirNames, "Parameter dirNames should be non-null");
+ Assert.assertTrue(dirNames.length > 0, "dirNames.length should be > 0");
+
+ StringBuffer dirName = new StringBuffer();
+ for(int i = 0; i < dirNames.length; i++) {
+ if(i > 0) {
+ dirName.append(File.separatorChar);
+ }
+ dirName.append(dirNames[i]);
+ }
+
+ return getPrivatePersistentDirectory(dirName.toString());
+ }
+
+ private String getFullPath(String fileName) {
+ Assert.assertNonNull(fileName, "The filename should be non-null.");
+
+ String userhome = null;
+ String sipSubdir = null;
+
+ // Obtain configuration service lock
+ synchronized(this.syncRoot) {
+ Assert.assertNonNull(this.configurationService,
+ "The configurationService should be non-null.");
+
+ userhome = this.configurationService.getString(FileAccessService.CONFPROPERTYKEY_USER_HOME);
+ sipSubdir = this.configurationService.getString(FileAccessService.CONFPROPERTYKEY_SIP_DIRECTORY);
+ }
+
+
+ if(userhome == null) {
+ userhome = System.getProperty(FileAccessService.SYSPROPERTYKEY_USER_HOME);
+ if(userhome == null) {
+ throw new IllegalStateException("No user home directory specified in system's environment");
+ }
+ }
+ if(sipSubdir == null) {
+ sipSubdir = FileAccessService.DEFAULT_SIP_DIRECTORY;
+ }
+
+ if(!userhome.endsWith(File.separator)) {
+ userhome += File.separator;
+ }
+ if(!sipSubdir.endsWith(File.separator)) {
+ sipSubdir += File.separator;
+ }
+
+ return userhome + sipSubdir;
+ }
+
+
+ /**
+ * Checks if a file exists and if it is writable or readable. If not - checks
+ * if the user has a write privileges to the containing directory.
+ *
+ * If those conditions are met it returns a File in the directory with a
+ * fileName. If not - returns null.
+ *
+ * @param homedir
+ * @param fileName
+ * @return Returns null if the file does not exist and cannot be created.
+ * Otherwise - an object to this file
+ * @throws IOException Thrown if the home directory cannot be created
+ */
+ private File accessibleFile(String homedir, String fileName) throws IOException {
+ File file = null;
+
+ try {
+ logger.logEntry();
+
+ homedir = homedir.trim();
+ if(!homedir.endsWith(File.separator)) {
+ homedir += File.separator;
+ }
+
+ file = new File(homedir + fileName);
+ if (file.canRead() || file.canWrite()) {
+ return file;
+ }
+
+ File homedirFile = new File(homedir);
+
+ if(!homedirFile.exists()) {
+ logger.debug("Creating home directory : " + homedirFile.getAbsolutePath());
+ if(!homedirFile.mkdirs()) {
+ String message = "Could not create the home directory : "
+ + homedirFile.getAbsolutePath();
+
+ logger.debug(message);
+ throw new IOException(message);
+ }
+ logger.debug("Home directory created : " + homedirFile.getAbsolutePath());
+ } else if (!homedirFile.canWrite()) {
+ file = null;
+ }
+
+ } finally {
+ logger.logExit();
+ }
+
+ return file;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/resources/TempFileManager.java b/src/net/java/sip/communicator/impl/resources/TempFileManager.java
new file mode 100644
index 0000000..a365125
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/resources/TempFileManager.java
@@ -0,0 +1,212 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.resources;
+
+import java.io.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * Generates and properly cleans up temporary files. Similar to {@link
+ * File#createTempFile(java.lang.String, java.lang.String)}, this class
+ * provides a static method to create temporary files. The temporary files will
+ * be created in a special directory to be cleaned up the next time this class
+ * is loaded by the JVM. This functionality is required because Win32 platforms
+ * will not allow the JVM to delete files that are open. This causes problems
+ * with items such as JARs that get opened by a URLClassLoader and can
+ * therefore not be deleted by the JVM (including deleteOnExit).
+ *
+ * The caller should not need to create an instance of this class, although it
+ * is possible. Simply use the static methods to perform the required
+ * operations. Note that all files created by this class should be
+ * considered as deleted at JVM exit (although the actual deletion may be
+ * delayed). If persistent temporary files are required, use {@link
+ * java.io.File} instead.
+ *
+ * Refer to Sun bugs 4171239 and 4950148 for more details.
+ */
+public class TempFileManager
+{
+
+ /**
+ * Creates a temporary file in the proper directory to allow for cleanup
+ * after execution. This method delegates to {@link
+ * File#createTempFile(java.lang.String, java.lang.String, java.io.File)} so
+ * refer to it for more documentation. Any file created using this method
+ * should be considered as deleted at JVM exit; therefore, do not use this
+ * method to create files that need to be persistent between application
+ * runs.
+ *
+ * @param prefix the prefix string used in generating the file name;
+ * must be at least three characters long
+ * @param suffix the suffix string to be used in generating the file's
+ * name; may be null, in which case the suffix ".tmp" will be used
+ * @return an abstract pathname denoting a newly created empty
+ * file
+ * @throws IOException if a file could not be created
+ */
+ public static File createTempFile(String prefix, String suffix)
+ throws IOException
+ {
+ // Check to see if you have already initialized a temp directory
+ // for this class.
+ if (sTmpDir == null)
+ {
+ // Initialize your temp directory. You use the java temp directory
+ // property, so you are sure to find the files on the next run.
+ String tmpDirName = System.getProperty("java.io.tmpdir");
+ File tmpDir = File.createTempFile(TEMP_DIR_PREFIX, ".tmp",
+ new File(tmpDirName));
+
+ // Delete the file if one was automatically created by the JVM.
+ // You are going to use the name of the file as a directory name,
+ // so you do not want the file laying around.
+ tmpDir.delete();
+
+ // Create a lock before creating the directory so
+ // there is no race condition with another application trying
+ // to clean your temp dir.
+ File lockFile = new File(tmpDirName, tmpDir.getName() + ".lck");
+ lockFile.createNewFile();
+
+ // Set the lock file to delete on exit so it is properly cleaned
+ // by the JVM. This will allow the TempFileManager to clean
+ // the overall temp directory next time.
+ lockFile.deleteOnExit();
+
+ // Make a temp directory that you will use for all future requests.
+ if (!tmpDir.mkdirs())
+ {
+ throw new IOException("Unable to create temporary directory:"
+ + tmpDir.getAbsolutePath());
+ }
+
+ sTmpDir = tmpDir;
+ }
+
+ // Generate a temp file for the user in your temp directory
+ // and return it.
+ return File.createTempFile(prefix, suffix, sTmpDir);
+ }
+
+
+ /**
+ * Deletes all of the files in the given directory, recursing into any sub
+ * directories found. Also deletes the root directory.
+ *
+ * @param rootDir the root directory to be recursively deleted
+ * @throws IOException if any file or directory could not be deleted
+ */
+ private static void recursiveDelete(File rootDir)
+ throws IOException
+ {
+ // Select all the files
+ File[] files = rootDir.listFiles();
+ for (int i = 0; i < files.length; i++)
+ {
+ // If the file is a directory, we will
+ // recursively call delete on it.
+ if (files[i].isDirectory())
+ {
+ recursiveDelete(files[i]);
+ }
+ else
+ {
+ // It is just a file so we are safe to
+ // delete it
+ if (!files[i].delete())
+ {
+ throw new IOException("Could not delete: " + files[i].getAbsolutePath());
+ }
+ }
+ }
+
+ // Finally, delete the root directory now
+ // that all of the files in the directory have
+ // been properly deleted.
+ if (!rootDir.delete())
+ {
+ throw new IOException("Could not delete: " + rootDir.getAbsolutePath());
+ }
+ }
+
+
+ /**
+ * The prefix for the temp directory in the system temp directory
+ */
+ private final static String TEMP_DIR_PREFIX = "tmp-mgr-";
+
+ /**
+ * The temp directory to generate all files in
+ */
+ private static File sTmpDir = null;
+
+ /**
+ * Static block used to clean up any old temp directories found -- the JVM
+ * will run this block when a class loader loads the class.
+ */
+ static
+ {
+ // Clean up any old temp directories by listing
+ // all of the files, using a filter that will
+ // return only directories that start with your
+ // prefix.
+ FileFilter tmpDirFilter =
+ new FileFilter()
+ {
+ public boolean accept(File pathname)
+ {
+ return (pathname.isDirectory() &&
+ pathname.getName().startsWith(TEMP_DIR_PREFIX));
+ }
+ };
+
+ // Get the system temp directory and filter the files.
+ String tmpDirName = System.getProperty("java.io.tmpdir");
+ File tmpDir = new File(tmpDirName);
+ File[] tmpFiles = tmpDir.listFiles(tmpDirFilter);
+
+ // Find all the files that do not have a lock by
+ // checking if the lock file exists.
+ for (int i = 0; i < tmpFiles.length; i++)
+ {
+ File tmpFile = tmpFiles[i];
+
+ // Create a file to represent the lock and test.
+ File lockFile = new File(tmpFile.getParent(), tmpFile.getName() + ".lck");
+ if (!lockFile.exists())
+ {
+ // Delete the contents of the directory since
+ // it is no longer locked.
+ Logger.getLogger("default").log(Level.FINE,
+ "TempFileManager::deleting old temp directory " + tmpFile);
+
+ try
+ {
+ recursiveDelete(tmpFile);
+ }
+ catch (IOException ex)
+ {
+ // You log at a fine level since not being able to delete
+ // the temp directory should not stop the application
+ // from performing correctly. However, if the application
+ // generates a lot of temp files, this could become
+ // a disk space problem and the level should be raised.
+ Logger.getLogger("default").log(Level.INFO,
+ "TempFileManager::unable to delete " + tmpFile.getAbsolutePath());
+
+ // Print the exception.
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+ ex.printStackTrace(new PrintStream(ostream));
+
+ Logger.getLogger("default").log(Level.FINE, ostream.toString());
+ }
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/resources/resources.manifest.mf b/src/net/java/sip/communicator/impl/resources/resources.manifest.mf
new file mode 100644
index 0000000..f73bbc6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/resources/resources.manifest.mf
@@ -0,0 +1,22 @@
+Bundle-Activator: net.java.sip.communicator.impl.resources.Activator
+Bundle-Name: Resources Management Service Provider
+Bundle-Description: A bundle that implements the resource management package.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.ungoverned.gravity.servicebinder,
+ org.osgi.framework,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.impl.resources,
+ org.w3c.dom,
+ org.xml.sax,
+ javax.xml.parsers,
+ org.apache.xml.serializer,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.xml,
+Export-Package: net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.impl.resources,
+Metadata-Location: /net/java/sip/communicator/impl/resources/resources.metadata.xml \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/resources/resources.metadata.xml b/src/net/java/sip/communicator/impl/resources/resources.metadata.xml
new file mode 100644
index 0000000..aa37573
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/resources/resources.metadata.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<bundle>
+ <component class="net.java.sip.communicator.impl.resources.FileAccessServiceImpl">
+ <provides service="net.java.sip.communicator.service.resources.FileAccessService"/>
+
+ <!--
+ One and only one reference to a configuration service is needed.
+ If this service is stopped, the file access service is also uninstalled
+ -->
+ <requires service="net.java.sip.communicator.service.configuration.ConfigurationService"
+ filter=""
+ policy="static"
+ cardinality="1..1"
+ bind-method="setConfigurationService"
+ unbind-method="unsetConfigurationService" />
+ </component>
+</bundle>
diff --git a/src/net/java/sip/communicator/launcher/Main.java b/src/net/java/sip/communicator/launcher/Main.java
new file mode 100644
index 0000000..ca296be
--- /dev/null
+++ b/src/net/java/sip/communicator/launcher/Main.java
@@ -0,0 +1,131 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.launcher;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import net.java.sip.communicator.util.Logger;
+
+import org.ungoverned.oscar.Noscar;
+import org.ungoverned.oscar.cache.DefaultBundleCache;
+import org.ungoverned.oscar.util.MutablePropertyResolver;
+import org.ungoverned.oscar.util.MutablePropertyResolverImpl;
+
+
+/**
+ * This is the main entry point of the program. It launches the Oscar OSGI
+ * Framework.
+ *
+ * @author Alexander Pelov
+ */
+public class Main {
+
+ public static final String CLIENT_RUN_PROPERTIES_FILE = "lib/oscar.client.run.properties";
+
+ /**
+ * The logger for this class.
+ */
+ private static Logger log = Logger.getLogger(Main.class);
+
+ private static Noscar oscar;
+
+ public static void main(String[] args) {
+
+ int errorStatus = -1;
+
+ try {
+ log.logEntry();
+
+ String oscarSystemPropertiesFile = System.getProperty("oscar.system.properties");
+ if(oscarSystemPropertiesFile == null) {
+ oscarSystemPropertiesFile = Main.CLIENT_RUN_PROPERTIES_FILE;
+ }
+
+ Properties props = Main.loadProperties(oscarSystemPropertiesFile);
+
+ // See if the profile name property was specified.
+ String profileName = System.getProperty(DefaultBundleCache.CACHE_PROFILE_PROP);
+
+ // See if the profile directory property was specified.
+ String profileDirName = System.getProperty(DefaultBundleCache.CACHE_PROFILE_DIR_PROP);
+
+ // If no profile or profile directory is specified in the
+ // properties, then ask for a profile name.
+ if ((profileName == null) && (profileDirName == null))
+ {
+ boolean cacheProfileSet = props.containsKey(DefaultBundleCache.CACHE_PROFILE_PROP);
+ boolean cacheProfileDirSet = props.containsKey(DefaultBundleCache.CACHE_PROFILE_DIR_PROP);
+
+ if(!cacheProfileSet && !cacheProfileDirSet) {
+ props.put(DefaultBundleCache.CACHE_PROFILE_PROP, ".sip-communicator");
+ }
+ }
+
+ MutablePropertyResolver propertyResolver =
+ new MutablePropertyResolverImpl(props);
+
+ Main.oscar = new Noscar();
+ Main.oscar.start(propertyResolver, null);
+
+ errorStatus = 0;
+ } catch(Exception e) {
+ log.error("Error occured while starting Oscar OSGI", e);
+
+ errorStatus = -1;
+ } finally {
+ log.logExit();
+ }
+
+ System.exit(errorStatus);
+ }
+
+ private static Properties loadProperties(String file) throws IOException {
+ int pos = file.indexOf(':');
+
+ // Test if the protocol is defined.
+ // It is set if ':' exists in the filename and if
+ // there is no path separator before it.
+ //
+ // Several characters are tested for file separator candidates:
+ // Window's '\', Unix's '/', and the separator of the current
+ // system.. Who knows.. maybe some day someone will use @ for file
+ // separator on @ix.. ;)
+ if(pos >= 0 &&
+ Main.isPosBeforeChar(file, pos, File.separatorChar) &&
+ Main.isPosBeforeChar(file, pos, '\\') &&
+ Main.isPosBeforeChar(file, pos, '/'))
+ {
+ file = file.substring(pos+1);
+ }
+
+ InputStream in = new FileInputStream(file);
+
+ Properties props = null;
+
+ try {
+ props = new Properties();
+ props.load(in);
+ } finally {
+ try {
+ in.close();
+ } catch(Exception e) {}
+ }
+
+ return props;
+ }
+
+ private static boolean isPosBeforeChar(String text, int pos, char c) {
+ int charPos = text.indexOf(c);
+
+ return charPos < 0 || pos < charPos;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/callhistory/CallHistoryService.java b/src/net/java/sip/communicator/service/callhistory/CallHistoryService.java
new file mode 100644
index 0000000..911e050
--- /dev/null
+++ b/src/net/java/sip/communicator/service/callhistory/CallHistoryService.java
@@ -0,0 +1,15 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+ package net.java.sip.communicator.service.callhistory;
+
+import net.java.sip.communicator.service.history.HistoryReader;
+
+/**
+ * @author Alexander Pelov
+ */
+public interface CallHistoryService extends HistoryReader {
+}
diff --git a/src/net/java/sip/communicator/service/configuration/ConfigurationService.java b/src/net/java/sip/communicator/service/configuration/ConfigurationService.java
new file mode 100644
index 0000000..ee15197
--- /dev/null
+++ b/src/net/java/sip/communicator/service/configuration/ConfigurationService.java
@@ -0,0 +1,201 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.configuration;
+
+import net.java.sip.communicator.service.configuration.event.*;
+import java.io.*;
+
+import net.java.sip.communicator.util.xml.*;
+
+/**
+ * The configuration services provides a centralized approach of storing
+ * persistent configuration data.
+ *
+ * @author Emil Ivov
+ */
+public interface ConfigurationService
+{
+ /**
+ * Sets the property with the specified name to the specified value. Calling
+ * this method would first trigger a PropertyChangeEvent that will
+ * be dispatched to all VetoableChangeListeners. In case no complaints
+ * (PropertyVetoException) have been received, the property will be actually
+ * changed and a PropertyChangeEvent will be dispatched.
+ * <p>
+ * @param propertyName the name of the property to change.
+ * @param property the new value of the specified property.
+ * @throws PropertyVetoException in case the changed has been refused by
+ * at least one propertychange listener.
+ */
+ public void setProperty(String propertyName, Object property)
+ throws PropertyVetoException;
+
+ /**
+ * Sets the property with the specified name to the specified. Calling
+ * this method would first trigger a PropertyChangeEvent that will
+ * be dispatched to all VetoableChangeListeners. In case no complaints
+ * (PropertyVetoException) have been received, the property will be actually
+ * changed and a PropertyChangeEvent will be dispatched. This method also
+ * allows the caller to specify whether or not the specified property is a
+ * system one.
+ * <p>
+ * @param propertyName the name of the property to change.
+ * @param property the new value of the specified property.
+ * @param isSystem specifies whether or not the property being is a System
+ * property and should be resolved against the system
+ * property set
+ * @throws PropertyVetoException in case the changed has been refused by
+ * at least one propertychange listener.
+ */
+ public void setProperty(String propertyName,
+ Object property,
+ boolean isSystem)
+ throws PropertyVetoException;
+
+ /**
+ * Returns the value of the property with the specified name or null if no
+ * such property exists.
+ * @param propertyName the name of the property that is being queried.
+ * @return the value of the property with the specified name.
+ */
+ public Object getProperty(String propertyName);
+
+ /**
+ * Returns the String value of the specified property and null in case no
+ * property value was mapped against the specified propertyName, or in
+ * case the returned property string had zero length or contained
+ * whitespaces only.
+ *
+ * @param propertyName the name of the property that is being queried.
+ * @return the result of calling the property's toString method and null in
+ * case there was no vlaue mapped against the specified
+ * <code>propertyName</code>, or the returned string had zero length or
+ * contained whitespaces only.
+ */
+ public String getString(String propertyName);
+
+ /**
+ * Adds a PropertyChangeListener to the listener list. The listener is
+ * registered for all properties in the current configuration.
+ * <p>
+ * @param listener the PropertyChangeListener to be added
+ */
+ public void addPropertyChangeListener(PropertyChangeListener listener);
+
+ /**
+ * Removes a PropertyChangeListener from the listener list.
+ * <p>
+ * @param listener the PropertyChangeListener to be removed
+ */
+ public void removePropertyChangeListener(PropertyChangeListener listener);
+
+ /**
+ * Adds a PropertyChangeListener to the listener list for a specific
+ * property. In case a property with the specified name does not exist the
+ * listener is still added and would only be taken into account from the
+ * moment such a property is set by someone.
+ * <p>
+ * @param propertyName one of the property names listed above
+ * @param listener the PropertyChangeListener to be added
+ */
+ public void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener);
+
+ /**
+ * Removes a PropertyChangeListener from the listener list for a specific
+ * property. This method should be used to remove PropertyChangeListeners
+ * that were registered for a specific property. The method has no effect
+ * when called for a listener that was not registered for that specifiec
+ * property.
+ * <p>
+ *
+ * @param propertyName a valid property name
+ * @param listener the PropertyChangeListener to be removed
+ */
+ public void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener);
+
+ /**
+ * Adds a VetoableChangeListener to the listener list. The listener is
+ * registered for all properties in the configuration.
+ * <p>
+ * @param listener the VetoableChangeListener to be added
+ */
+ public void addVetoableChangeListener(VetoableChangeListener listener);
+
+ /**
+ * Removes a VetoableChangeListener from the listener list.
+ * <p>
+ *
+ * @param listener the VetoableChangeListener to be removed
+ */
+ public void removeVetoableChangeListener(VetoableChangeListener listener);
+
+ /**
+ * Adds a VetoableChangeListener to the listener list for a specific
+ * property.
+ * <p>
+ *
+ * @param propertyName one of the property names listed above
+ * @param listener the VetoableChangeListener to be added
+ */
+ public void addVetoableChangeListener(String propertyName,
+ VetoableChangeListener listener);
+
+ /**
+ * Removes a VetoableChangeListener from the listener list for a specific
+ * property.
+ * <p>
+ *
+ * @param propertyName a valid property name
+ * @param listener the VetoableChangeListener to be removed
+ */
+ public void removeVetoableChangeListener(String propertyName,
+ VetoableChangeListener listener);
+
+ /**
+ * Store the current set of properties back to the configuration file. The
+ * name of the configuration file is queried from the system property
+ * net.java.sip.communicator.PROPERTIES_FILE_NAME, and is set to
+ * sip-communicator.xml in case the property does not contain a valid file
+ * name. The location might be one of three possibile, checked in the
+ * following order: <br>
+ * 1. The current directory. <br>
+ * 2. The sip-communicator directory in the user.home
+ * ($HOME/.sip-communicator)
+ * 3. A location in the classpath (such as the sip-communicator jar file).
+ * <p>
+ * In the last case the file is copied to the sip-communicator configuration
+ * directory right after being extracted from the classpath location.
+ *
+ * @throws IOException in case storing the configuration failed.
+ */
+ public void storeConfiguration()
+ throws IOException;
+
+ /**
+ * Deletes the current configuration and reloads it from the configuration
+ * file. The
+ * name of the configuration file is queried from the system property
+ * net.java.sip.communicator.PROPERTIES_FILE_NAME, and is set to
+ * sip-communicator.xml in case the property does not contain a valid file
+ * name. The location might be one of three possibile, checked in the
+ * following order: <br>
+ * 1. The current directory. <br>
+ * 2. The sip-communicator directory in the user.home
+ * ($HOME/.sip-communicator)
+ * 3. A location in the classpath (such as the sip-communicator jar file).
+ * <p>
+ * In the last case the file is copied to the sip-communicator configuration
+ * directory right after being extracted from the classpath location.
+ * @throws IOException in case reading the configuration failes
+ * @throws XMLException in case parsing the configuration file has failed
+ */
+ public void reloadConfiguration()
+ throws IOException, XMLException;
+
+}
diff --git a/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java b/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java
new file mode 100644
index 0000000..dd57f95
--- /dev/null
+++ b/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java
@@ -0,0 +1,50 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.configuration;
+
+import net.java.sip.communicator.service.configuration.event.*;
+import net.java.sip.communicator.util.xml.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+
+/**
+ * A PropertyVetoException is thrown when a proposed change to a
+ * property represents an unacceptable value.
+ *
+ * @author Emil Ivov
+ */
+public class PropertyVetoException
+ extends Exception
+{
+ /**
+ * A PropertyChangeEvent describing the vetoed change.
+ * @serial
+ */
+ private PropertyChangeEvent evt;
+
+ /**
+ * Constructs a <code>PropertyVetoException</code> with a
+ * detailed message.
+ *
+ * @param mess Descriptive message
+ * @param evt A PropertyChangeEvent describing the vetoed change.
+ */
+ public PropertyVetoException(String mess, PropertyChangeEvent evt)
+ {
+ super(mess);
+ this.evt = evt;
+ }
+
+ /**
+ * Gets the vetoed <code>PropertyChangeEvent</code>.
+ *
+ * @return A PropertyChangeEvent describing the vetoed change.
+ */
+ public PropertyChangeEvent getPropertyChangeEvent()
+ {
+ return evt;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/configuration/event/PropertyChangeEvent.java b/src/net/java/sip/communicator/service/configuration/event/PropertyChangeEvent.java
new file mode 100644
index 0000000..641a8c5
--- /dev/null
+++ b/src/net/java/sip/communicator/service/configuration/event/PropertyChangeEvent.java
@@ -0,0 +1,109 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.configuration.event;
+
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.util.xml.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+
+/**
+ * A "ConfigurationChange" event gets delivered whenever a someone changes a
+ * configuration property. A ConfigurationEvent object is sent as an
+ * argument to the ConfigurationChangeListener methods.
+ * <P>
+ * Normally ConfigurationChangeEvents are accompanied by the name and the old
+ * and new values of the changed property. If the new value is a primitive
+ * type (such as int or boolean) it must be wrapped as the
+ * corresponding java.lang.* Object type (such as Integer or Boolean).
+ * <P>
+ * Null values may be provided for the old and the new values if their
+ * true values are not known.
+ * <P>
+ * An event source may send a null object as the name to indicate that an
+ * arbitrary set of if its properties have changed. In this case the
+ * old and new values should also be null.
+ * <P>
+ * In the case where the event reflects the change of a constrained property,
+ * it will first be dispatched to all propertyWillChange methods and only in
+ * case that none of them has objected (no ChangeVetoException has been thrown)
+ * the propertyChange method is called.
+ *
+ * @author Emil Ivov
+ */
+public class PropertyChangeEvent
+ extends java.util.EventObject
+{
+
+ /**
+ * name of the property that changed. May be null, if not known.
+ * @serial
+ */
+ private String propertyName;
+
+ /**
+ * New value for property. May be null if not known.
+ * @serial
+ */
+ private Object newValue;
+
+ /**
+ * Previous value for property. May be null if not known.
+ * @serial
+ */
+ private Object oldValue;
+
+ /**
+ * Constructs a new <code>PropertyChangeEvent</code>.
+ *
+ * @param source The bean that fired the event.
+ * @param propertyName The programmatic name of the property
+ * that was changed.
+ * @param oldValue The old value of the property.
+ * @param newValue The new value of the property.
+ */
+ public PropertyChangeEvent(Object source, String propertyName,
+ Object oldValue, Object newValue)
+ {
+ super(source);
+ this.propertyName = propertyName;
+ this.newValue = newValue;
+ this.oldValue = oldValue;
+ }
+
+ /**
+ * Gets the programmatic name of the property that was changed.
+ *
+ * @return The programmatic name of the property that was changed.
+ * May be null if multiple properties have changed.
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+
+ /**
+ * Sets the new value for the property, expressed as an Object.
+ *
+ * @return The new value for the property, expressed as an Object.
+ * May be null if multiple properties have changed.
+ */
+ public Object getNewValue()
+ {
+ return newValue;
+ }
+
+ /**
+ * Gets the old value for the property, expressed as an Object.
+ *
+ * @return The old value for the property, expressed as an Object.
+ * May be null if multiple properties have changed.
+ */
+ public Object getOldValue()
+ {
+ return oldValue;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/configuration/event/PropertyChangeListener.java b/src/net/java/sip/communicator/service/configuration/event/PropertyChangeListener.java
new file mode 100644
index 0000000..fe9b05f
--- /dev/null
+++ b/src/net/java/sip/communicator/service/configuration/event/PropertyChangeListener.java
@@ -0,0 +1,29 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.configuration.event;
+
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.util.xml.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+
+/**
+ * A "ConfigurationChange" event gets fired whenever a configuration property
+ * changes. Depending on whether the property was constrained or not, the
+ * propertyChange or vetoableChange methods get called.
+ *
+ * @author Emil Ivov
+ */
+public interface PropertyChangeListener
+{
+ /**
+ * This method gets called when a bound property is changed.
+ * @param evt A PropertyChangeEvent object describing the event source
+ * and the property that has changed.
+ */
+ void propertyChange(PropertyChangeEvent evt);
+
+}
diff --git a/src/net/java/sip/communicator/service/configuration/event/VetoableChangeListener.java b/src/net/java/sip/communicator/service/configuration/event/VetoableChangeListener.java
new file mode 100644
index 0000000..2f09263
--- /dev/null
+++ b/src/net/java/sip/communicator/service/configuration/event/VetoableChangeListener.java
@@ -0,0 +1,46 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.configuration.event;
+
+import java.util.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.util.xml.*;
+import net.java.sip.communicator.impl.configuration.xml.*;
+
+/**
+ * A VetoableChange event gets fired whenever a property is about to change.
+ * One can register a VetoableChangeListener with the ConfigurationService so as
+ * to be notified in advance of any property updates. The purpose of a
+ * VetoableChaneListener is that it allows registered instances to veto or in
+ * other words cancel events by throwing a PropertyVetoException. In case
+ * none of the registered listeners has thrown an exception, the property is
+ * changed and a propertyChange event is dispatched to all registered
+ * PropertyChangeListener-s
+ *
+ * @author Emil Ivov
+ */
+public interface VetoableChangeListener
+ extends EventListener
+{
+
+ /**
+ * This method gets called when a constrained property is about to change.
+ * Note that the method only warns about the change and in case none of
+ * the interested listeners vetos it (i.e. no PropertyVetoException
+ * is thrown) the propedrtyChange method will be called next to indicate
+ * that the change has taken place. In case you don't want to be notified
+ * for pending changes over constained properties you should provide
+ * an empty implementation of the method.
+ *
+ * @param evt a <code>PropertyChangeEvent</code> object describing the
+ * event source and the property that has changed.
+ * @exception PropertyVetoException if the recipient wishes the property
+ * change to be rolled back.
+ */
+ void vetoableChange(PropertyChangeEvent evt)
+ throws PropertyVetoException;
+}
diff --git a/src/net/java/sip/communicator/service/configuration/gravity-metadata.xml b/src/net/java/sip/communicator/service/configuration/gravity-metadata.xml
new file mode 100644
index 0000000..4827372
--- /dev/null
+++ b/src/net/java/sip/communicator/service/configuration/gravity-metadata.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bundle>
+ <!--
+ This metadata file instructs the Gravity Service Binder to
+ create one instance of "SpellCheckServiceImpl". It also
+ tells the generic activator that this instance implements the
+ "SpellCheckService" service interface and that it has an
+ aggregate dependency on "DictionaryService" services. Since
+ the service dependency on dictionary services has a lower
+ cardinality of one, the generic activator will create the instance
+ and offer its spell check service only when there is at least
+ one dictionary service available. The service dependency is
+ "dynamic", which means that dictionary service availability
+ will be monitored dynamically at runtime and it also tells the
+ generic activator which methods to call when adding and removing
+ dictionary services.
+ -->
+ <instance class="tutorial.example7.SpellCheckServiceImpl">
+ <service interface="net.java.sip.communicator.service.configuration.ConfigurationService"/>
+ <requires
+ service="tutorial.example2.service.DictionaryService"
+ filter="(Language=*)"
+ cardinality="1..n"
+ policy="dynamic"
+ bind-method="addDictionary"
+ unbind-method="removeDictionary"
+ />
+ </instance>
+</bundle>
diff --git a/src/net/java/sip/communicator/service/gui/UIService.java b/src/net/java/sip/communicator/service/gui/UIService.java
new file mode 100644
index 0000000..05127b1
--- /dev/null
+++ b/src/net/java/sip/communicator/service/gui/UIService.java
@@ -0,0 +1,155 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.gui;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The UIService provides an interface towards towards that part of the
+ * SIP Communicator that interacts with users and offers them a way to make,
+ * accept, manage or handup calls.
+ *
+ * In order for the UIService to support a communications protocol, a
+ * Provider implementation of the specified protocol needs to be registered with
+ * the service.
+ *
+ * Plugins using the service in order to add featuress to the user interface
+ * may do that using one of the addXxx() methods.
+ *
+ *
+ * @author Emil Ivov
+ */
+public interface UIService
+{
+ public static final String COMPONENT_CONSTRAINT_MENU_FILE = "File";
+ public static final String COMPONENT_CONSTRAINT_MENU_VIEW = "View";
+ public static final String COMPONENT_CONSTRAINT_MENU_TOOLS = "Tools";
+ public static final String COMPONENT_CONSTRAINT_MENU_SETTINGS = "Settings";
+ public static final String COMPONENT_CONSTRAINT_MENU_HELP = "Help";
+ public static final String COMPONENT_CONSTRAINT_MENU_CALL = "Call";
+ public static final String COMPONENT_CONSTRAINT_MENU_ACCOUNT = "Account";
+ public static final String COMPONENT_CONSTRAINT_MENU_CONTACT = "Contact";
+ public static final String COMPONENT_CONSTRAINT_MENU_BAR = "Menu Bar";
+
+ public static final String UI_LIB_SWING = "Swing";
+ public static final String UI_LIB_SWT = "SWT";
+ public static final String UI_LIB_AWT = "AWT";
+
+ /**
+ * Registers the specified telephony provider with the user interface. The
+ * PhoneUIService implementation will automatically add itself as a state
+ * listener of the specified provider and react in accordance with states
+ * coming from that listener. It will also deliver all relevant user
+ * call control requests to that provider.
+ * @param provider the provider to register.
+ */
+ public void registerProvider(ProtocolProviderService provider);
+
+ /**
+ * Specifies whether or not the phone ui should be visible (In case for
+ * example we'd only like a sys tray icon or a contact list to show).
+ * @param visible a boolean specifying whether the phone ui should be visible
+ */
+ public void setVisible(boolean visible);
+
+ //services offered to bundles/plugins that would like to interact with the
+ //gui.
+ /**
+ * Returns an array of Call objects containing the current set of ongoing
+ * calls. One could obtain specific call participants through by querying
+ * Call methods
+ * @return an array of Call objects reflecting on-going calls.
+ */
+ public Call[] getActiveCalls();
+
+ /**
+ * Returns the name of the library used to implement the service. In case
+ * the implementation is using Swing, SWT, or pure AWT it MUST return one of
+ * the UI_LIB_XXX constants. The method may be used by plugins that would
+ * like to retrieve ui components
+ * @return String
+ */
+ public String getUiLibName();
+
+ /**
+ * Returns an array of UI lib names indicating that the implementation is
+ * able to handle components registered by external plugins/bungles in case
+ * they are implemented using one of the returned lib names. The lib names
+ * returned by this method should be one or more of the UI_LIB_XXX constants,
+ * but callers of this method must properly handle unknown Strings which might
+ * be returned by implementations of future versions of this service.
+ *
+ * @return an array containing one or more UI_LIB_XXX constants.
+ */
+ public String[] getSupportedUiLibNames();
+
+ /**
+ * Adds the specified menuItem to the specified parent menu. The parent String
+ * MUST be one of the MENU_XXX constants. It is up to the service
+ * implementation to verify that "menuItem" is an instance of a class
+ * compatible with the gui library used by it. If this is not the case and
+ * adding the requested object would not be possible the implementation
+ * MUST through an exception.
+ *
+ * @param parent one of the MENU_XXX string constants indicating the parent
+ * menu that this menuItem should be added to.
+ * @param menuItem the item to add.
+ * @throws ClassCastException if the menuItem is an
+ * instance of a class not supported by the service implementation.
+ * @throws IllegalArgumentException if the specified parent is not
+ * recognized by the implementation (note that implementations MUST properly
+ * handle all MENU_XXX strings as eventual parents even if they do not
+ * correspond to a menu with the same title and may be organized at the will
+ * of the implementor).
+ */
+ public void addMenuItem(String parent, Object menuItem)
+ throws ClassCastException, IllegalArgumentException;
+
+ /**
+ * Adds the specified UI component to the user interface according to the
+ * provided string constraint. The method is meant to be used by plugins or
+ * bundles that would like to add components to the user interface. The
+ * <code>constraint</code> string is used by the implementation to determine
+ * the place where the component should be added. The <code>constraint</code>
+ * String SHOULD be one of the COMPONENT_CONSTRAINT_XXX constants. It is up
+ * to the service implementation to verify that <code>component</code> is an
+ * instance of a class compatible with the gui library used by it. If this
+ * is not the case and adding the requested object would not be possible the
+ * implementation MUST through a ClassCastException exception.
+ * Implementations of this service MUST understant and know how to handle
+ * all COMPONENT_CONSTRAINT_XXX Strings defined by this interface, they
+ * MAY also define additional constraints. In case the addComponent method
+ * is called with a <code>constraint</code> that the implementation does
+ * not understand it MUST through a java.lang.IllegalArgumentException <br>
+ * <br>
+ * @param component the component we'd like to add
+ * @param constraint a String (possibly one of the COMPONENT_CONSTRAINT_XXX
+ * strings) indicating the place where the component should be added.
+ * @throws ClassCastException if <code>component</code> is not an
+ * instance of a class supported by the service implementation. An SWT impl
+ * would, for example through a ClassCastException if handed a
+ * java.awt.Component
+ * @throws IllegalArgumentException if the specified <code>constraint</code>
+ * is not recognized by the implementation (note that implementations
+ * MUST properly handle all COMPONENT_CONSTRAINT_XXX strings.
+ */
+ public void addComponent(Object component, String constraint)
+ throws ClassCastException, IllegalArgumentException;
+
+ public void addUserActionListener();
+
+ //========================== CONFIG ======================================
+ //maybe add a method to show the config dialog
+
+ //========================== AuthenticationService =======================
+ //these should probably go to a different service
+ public void requestAuthentication(String realm, String userName,
+ char[] password);
+ public String getAuthenticationUserName();
+
+ //get main frame (for dialogs)
+}
diff --git a/src/net/java/sip/communicator/service/gui/event/UserActionListener.java b/src/net/java/sip/communicator/service/gui/event/UserActionListener.java
new file mode 100644
index 0000000..8a4fa1e
--- /dev/null
+++ b/src/net/java/sip/communicator/service/gui/event/UserActionListener.java
@@ -0,0 +1,44 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+ package net.java.sip.communicator.service.gui.event;
+
+import net.java.sip.communicator.service.protocol.event.*;
+
+/**
+ * The UserActionListener allows interested parties (such as a telephony
+ * protocol implementation) to register for notifications upon user requests
+ * relating to conversation management (such as establishing or ending a call
+ * with a specified call participant). The reason that we use such an
+ * EventListener rather that putting all these methods in a Provider and
+ * letting the Provider implementation handle them is that the user interface
+ * is not supposed to show any intelligence concerning telephony. It is not,
+ * for example, supposed to know that sip:emcho@sipphone.com is a sip URI and
+ * not a phone number. Listening telephony providers on the other hand would be
+ * able to recognize URIs they know how to handle and handle the event as well
+ * as call its consume() method so that it is not dispatched to other
+ * listeners.
+ * @author Emil Ivov
+ */
+public interface UserActionListener
+ extends java.util.EventListener
+{
+ /**
+ *
+ * @param evt CalleeInvitationEvent
+ */
+ public void handleHangupRequest(CallParticipantControlEvent evt);
+
+ public void handleAnswerRequest(CallParticipantControlEvent evt);
+
+ /**
+ * @todo add some a target url to the call control listener
+ * @param evt UserCallControlEvent
+ */
+ public void handleTransferRequest(CallParticipantControlEvent evt);
+
+ public void handleExitRequest();
+}
diff --git a/src/net/java/sip/communicator/service/history/DefaultQueryResultSet.java b/src/net/java/sip/communicator/service/history/DefaultQueryResultSet.java
new file mode 100644
index 0000000..2dc21bb
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/DefaultQueryResultSet.java
@@ -0,0 +1,65 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */package net.java.sip.communicator.service.history;
+
+import java.util.NoSuchElementException;
+import java.util.Vector;
+
+import net.java.sip.communicator.service.history.records.HistoryRecord;
+
+/**
+ * @author Alexander Pelov
+ */
+public class DefaultQueryResultSet implements QueryResultSet {
+
+ private Vector records = new Vector();
+ private int currentPos = -1;
+
+ public DefaultQueryResultSet(Vector records) {
+ this.records = records;
+ }
+
+ public HistoryRecord nextRecord() throws NoSuchElementException {
+ return (HistoryRecord)this.next();
+ }
+
+ public HistoryRecord prevRecord() throws NoSuchElementException {
+ return (HistoryRecord)this.prev();
+ }
+
+ public boolean hasPrev() {
+ return this.currentPos-1 >= 0;
+ }
+
+ public Object prev() throws NoSuchElementException {
+ this.currentPos--;
+
+ if(this.currentPos < 0) {
+ throw new NoSuchElementException();
+ }
+
+ return records.get(this.currentPos);
+ }
+
+ public boolean hasNext() {
+ return this.currentPos+1 < this.records.size();
+ }
+
+ public Object next() {
+ this.currentPos++;
+
+ if(this.currentPos >= this.records.size()) {
+ throw new NoSuchElementException();
+ }
+
+ return records.get(this.currentPos);
+ }
+
+ public void remove() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Cannot remove elements " +
+ "from underlaying collection.");
+ }
+}
diff --git a/src/net/java/sip/communicator/service/history/History.java b/src/net/java/sip/communicator/service/history/History.java
new file mode 100644
index 0000000..b71a1e5
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/History.java
@@ -0,0 +1,38 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history;
+
+import net.java.sip.communicator.service.history.records.HistoryRecordStructure;
+
+/**
+ * @author Alexander Pelov
+ */
+public interface History {
+
+ /**
+ * @return Returns an object which can be used to read and query
+ * this history.
+ */
+ HistoryReader getReader();
+
+ /**
+ * @return Returns an object which can be used to append records to
+ * this history.
+ */
+ HistoryWriter getWriter();
+
+ /**
+ * @return Returns the ID of this history.
+ */
+ HistoryID getID();
+
+ /**
+ * @return Returns the structure of the history records in this history.
+ */
+ HistoryRecordStructure getHistoryRecordsStructure();
+
+}
diff --git a/src/net/java/sip/communicator/service/history/HistoryID.java b/src/net/java/sip/communicator/service/history/HistoryID.java
new file mode 100644
index 0000000..f1b4714
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/HistoryID.java
@@ -0,0 +1,216 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history;
+
+import net.java.sip.communicator.util.Assert;
+
+/**
+ * Object used to uniquely identify a group of history records.
+ *
+ * @author Alexander Pelov
+ */
+public class HistoryID {
+
+ private String[] id;
+
+ private String stringRepresentation;
+
+ private int hashCode;
+
+ private HistoryID(String[] id) {
+ this.id = id;
+
+ StringBuffer buff = new StringBuffer();
+ for(int i = 0; i < id.length; i++) {
+ if(i > 0) buff.append(' ');
+ buff.append(this.id[i]);
+ }
+
+ this.stringRepresentation = buff.toString();
+ this.hashCode = this.stringRepresentation.hashCode();
+ }
+
+ /**
+ * Create a HistoryID from a raw ID. You can pass any kind of
+ * strings and they will be safely converted to valid IDs.
+ */
+ public static HistoryID createFromRawID(String[] rawid) {
+ Assert.assertNonNull(rawid, "Parameter RAWID should be non-null");
+ Assert.assertTrue(rawid.length > 0, "RAWID.length should be > 0");
+
+ String[] id = new String[rawid.length];
+ for(int i = 0; i < rawid.length; i++) {
+ id[i] = HistoryID.readableHash(rawid[i]);
+ }
+
+ return new HistoryID(id);
+ }
+
+ /**
+ * Create a HistoryID from a valid ID. You should pass only
+ * valid IDs (ones produced from readableHash).
+ *
+ * @throws IllegalArgumentException Thrown if a string from the ID is not
+ * valid an exception.
+ */
+ public static HistoryID createFromID(String[] id)
+ throws IllegalArgumentException
+ {
+ Assert.assertNonNull(id, "Parameter ID should be non-null");
+ Assert.assertTrue(id.length > 0, "ID.length should be > 0");
+
+ for(int i = 0; i < id.length; i++) {
+ if(!HistoryID.isIDValid(id[i])) {
+ throw new IllegalArgumentException("Not a valid ID: " + id[i]);
+ }
+ }
+
+ String[] newID = new String[id.length];
+ System.arraycopy(id, 0, newID, 0, id.length);
+ return new HistoryID(newID);
+ }
+
+ public String[] getID() {
+ return this.id;
+ }
+
+ public String toString() {
+ return this.stringRepresentation;
+ }
+
+ public int hashCode() {
+ return this.hashCode;
+ }
+
+ public boolean equals(Object obj) {
+ boolean eq = false;
+
+ if(obj instanceof HistoryID) {
+ String[] id = ((HistoryID)obj).id;
+
+ if(this.id.length == id.length) {
+ for(int i = 0; i < id.length; i++) {
+ String s1 = id[i];
+ String s2 = this.id[i];
+
+ if(!((s1 == s2) || (s1 != null && s1.equals(s2)))) {
+ eq = false;
+ break;
+ }
+ }
+ }
+ }
+
+ return eq;
+ }
+
+ /**
+ * An one-way function returning a "human readable" containing no special
+ * characters. All characters _, a-z, A-Z, 0-9 are kept unchainged.
+ * All other are replaced with _ and the word is postfixed with
+ * %HASHCODE, where HASHCODE is the hexadecimal hash value of the
+ * original string. If there are no special characters the word is
+ * not postfixed.
+ *
+ * Note: This method does not use URLEncoder, because in url-encoding
+ * the * sign is considered as "safe".
+ *
+ * @param rawString The string to be hashed.
+ * @return The human-readable hash.
+ */
+ public static String readableHash(String rawString) {
+ StringBuffer encodedString = new StringBuffer(rawString);
+ boolean addHash = false;
+
+ for(int i = 0; i < encodedString.length(); i++) {
+ if(HistoryID.isSpecialChar(encodedString.charAt(i))) {
+ addHash = true;
+ encodedString.setCharAt(i, '_');
+ }
+ }
+
+ if(addHash) {
+ encodedString.append('%');
+ encodedString.append(Integer.toHexString(rawString.hashCode()));
+ }
+
+ return encodedString.toString();
+ }
+
+ /**
+ * Tests if an ID is valid.
+ */
+ private static boolean isIDValid(String id) {
+ boolean isValid = true;
+
+ int pos = id.indexOf('%');
+ if(pos < 0) {
+ // There is no % in the id. In order to be valid all characters
+ // should be non-special
+ isValid = !hasSpecialChar(id);
+ } else {
+ // There is a % sign in the id. In order to be valid it has
+ // to be in the form X..X%Y..Y, where there should be no
+ // special characters in X..X, and Y..Y should be a hexadecimal
+ // number
+ if(pos+1 < id.length()) {
+ String start = id.substring(0, pos);
+ String end = id.substring(pos+1);
+
+ // Check X..X
+ isValid = !hasSpecialChar(start);
+ if(isValid) {
+ // OK; Check Y..Y
+ try {
+ Integer.parseInt(end, 16);
+ // OK
+ isValid = true;
+ } catch(Exception e) {
+ // Not OK
+ isValid = false;
+ }
+ }
+ } else {
+ // The % sign is in the beginning - bad ID.
+ isValid = false;
+ }
+ }
+
+ return isValid;
+ }
+
+ /**
+ * Tests if a character is a special one. A character is special
+ * if it is not in the range _, a-z, A-Z, 0-9.
+ *
+ * @param c The character to test.
+ * @return Returns true if the character is special. False otherwise.
+ */
+ private static boolean isSpecialChar(char c) {
+ return (c != '_') &&
+ (c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z') &&
+ (c < '0' || c > '9');
+ }
+
+ /**
+ * Tests there is a special character in a string.
+ */
+ private static boolean hasSpecialChar(String str) {
+ boolean hasSpecialChar = false;
+
+ for(int i = 0; i < str.length(); i++) {
+ if(isSpecialChar(str.charAt(i))) {
+ hasSpecialChar = false;
+ break;
+ }
+ }
+
+ return hasSpecialChar;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/history/HistoryReader.java b/src/net/java/sip/communicator/service/history/HistoryReader.java
new file mode 100644
index 0000000..8ae3f3d
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/HistoryReader.java
@@ -0,0 +1,74 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history;
+
+import java.util.Date;
+
+/**
+ * @author Alexander Pelov
+ */
+public interface HistoryReader {
+
+ /**
+ * Searches the history for all records with timestamp
+ * after <code>startDate</code>.
+ *
+ * @throws RuntimeException Thrown if an exception occurs during
+ * the execution of the query, such as internal IO error.
+ */
+ QueryResultSet findByStartDate(Date startDate)
+ throws RuntimeException;
+
+ /**
+ * Searches the history for all records with timestamp
+ * before <code>endDate</code>.
+ *
+ * @throws RuntimeException Thrown if an exception occurs during
+ * the execution of the query, such as internal IO error.
+ */
+ QueryResultSet findByEndDate(Date endDate)
+ throws RuntimeException;
+
+ /**
+ * Searches the history for all records with timestamp
+ * between <code>startDate</code> and <code>endDate</code>.
+ *
+ * @throws RuntimeException Thrown if an exception occurs during
+ * the execution of the query, such as internal IO error.
+ */
+ QueryResultSet findByPeriod(Date startDate, Date endDate)
+ throws RuntimeException;
+
+ /**
+ * Searches the history for all records containing the <code>keyword</code>.
+ *
+ * @throws RuntimeException Thrown if an exception occurs during
+ * the execution of the query, such as internal IO error.
+ */
+ QueryResultSet findByKeyword(String keyword)
+ throws RuntimeException;
+
+ /**
+ * Searches the history for all records containing all <code>keywords</code>.
+ *
+ * @throws RuntimeException Thrown if an exception occurs during
+ * the execution of the query, such as internal IO error.
+ */
+ QueryResultSet findByKeywords(String[] keywords)
+ throws RuntimeException;
+
+ /**
+ * Searches for all history records containing all <code>keywords</code>,
+ * with timestamp between <code>startDate</code> and <code>endDate</code>.
+ *
+ * @throws RuntimeException Thrown if an exception occurs during
+ * the execution of the query, such as internal IO error.
+ */
+ QueryResultSet findByText(Date startDate, Date endDate, String[] keywords)
+ throws UnsupportedOperationException;
+
+}
diff --git a/src/net/java/sip/communicator/service/history/HistoryService.java b/src/net/java/sip/communicator/service/history/HistoryService.java
new file mode 100644
index 0000000..1d8cc5e
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/HistoryService.java
@@ -0,0 +1,62 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import net.java.sip.communicator.service.history.records.HistoryRecordStructure;
+
+/**
+ * This service provides the functionality to store history records. The
+ * records are called <code>HistoryRecord</code>s and are grouped by ID.
+ *
+ * The ID may be used to set hierarchical structure. In a typical usage one
+ * may set the first string to be the userID, and the second - the service name.
+ *
+ * @author Alexander Pelov
+ */
+public interface HistoryService {
+
+ /**
+ * Returns the IDs of all existing histories.
+ *
+ * @return An iterator to a list of IDs.
+ */
+ Iterator getExistingIDs();
+
+ /**
+ * Returns the history associated with this ID.
+ *
+ * @param id The ID of the history.
+ * @return Returns the history with this ID.
+ * @throws IllegalArgumentException Thrown if there is no such history.
+ */
+ History getHistory(HistoryID id)
+ throws IllegalArgumentException;
+
+ /**
+ * Tests if a history with the given ID exists.
+ *
+ * @param id The ID to test.
+ * @return True if a history with this ID exists. False otherwise.
+ */
+ boolean isHistoryExisting(HistoryID id);
+
+ /**
+ * Creates a new history for this ID.
+ *
+ * @param id The ID of the history to be created.
+ * @param recordStructure The structure of the data.
+ * @return Returns the history with this ID.
+ * @throws IllegalArgumentException Thrown if such history already exists.
+ * @throws IOException Thrown if the history could not be created due to
+ * a IO error.
+ */
+ History createHistory(HistoryID id, HistoryRecordStructure recordStructure)
+ throws IllegalArgumentException, IOException;
+}
diff --git a/src/net/java/sip/communicator/service/history/HistoryWriter.java b/src/net/java/sip/communicator/service/history/HistoryWriter.java
new file mode 100644
index 0000000..cba2bd1
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/HistoryWriter.java
@@ -0,0 +1,36 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history;
+
+import java.io.IOException;
+
+import net.java.sip.communicator.service.history.records.HistoryRecord;
+
+/**
+ * @author Alexander Pelov
+ */
+public interface HistoryWriter {
+
+ /**
+ * Stores the passed record complying with the historyRecordStructure.
+ *
+ * @param record The record to be added.
+ *
+ * @throws IOException
+ */
+ void addRecord(HistoryRecord record) throws IOException;
+
+ /**
+ * Stores the passed propertyValues complying with the historyRecordStructure.
+ *
+ * @param propertyValues The values of the record.
+ *
+ * @throws IOException
+ */
+ void addRecord(String[] propertyValues) throws IOException;
+
+}
diff --git a/src/net/java/sip/communicator/service/history/QueryResultSet.java b/src/net/java/sip/communicator/service/history/QueryResultSet.java
new file mode 100644
index 0000000..968c0c6
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/QueryResultSet.java
@@ -0,0 +1,39 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history;
+
+import java.util.NoSuchElementException;
+
+import net.java.sip.communicator.service.history.records.HistoryRecord;
+import net.java.sip.communicator.util.BidirectionalIterator;
+
+
+/**
+*
+* @author Alexander Pelov
+*/
+public interface QueryResultSet extends BidirectionalIterator {
+
+ /**
+ * A strongly-typed variant of <code>next()</code>.
+ *
+ * @return the next history record.
+ *
+ * @throws NoSuchElementException iteration has no more elements.
+ */
+ HistoryRecord nextRecord() throws NoSuchElementException;
+
+ /**
+ * A strongly-typed variant of <code>prev()</code>.
+ *
+ * @return the previous history record.
+ *
+ * @throws NoSuchElementException iteration has no more elements.
+ */
+ HistoryRecord prevRecord() throws NoSuchElementException;
+
+}
diff --git a/src/net/java/sip/communicator/service/history/records/HistoryRecord.java b/src/net/java/sip/communicator/service/history/records/HistoryRecord.java
new file mode 100644
index 0000000..7572892
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/records/HistoryRecord.java
@@ -0,0 +1,90 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history.records;
+
+import java.util.Date;
+
+import net.java.sip.communicator.util.Assert;
+
+/**
+ * @author Alexander Pelov
+ */
+public class HistoryRecord {
+
+ private Date timestamp;
+ private String[] propertyNames;
+ private String[] propertyValues;
+
+ /**
+ * Constructs an entry containing multiple name-value pairs, where the names
+ * are taken from the defined structure. The timestamp is set to the time this
+ * object is created.
+ *
+ * @param entryStructure
+ * @param propertyValues
+ */
+ public HistoryRecord(HistoryRecordStructure entryStructure, String[] propertyValues) {
+ this(entryStructure.getPropertyNames(), propertyValues, new Date());
+ }
+
+ /**
+ * Constructs an entry containing multiple name-value pairs, where the name is not
+ * unique. The timestamp is set to the time this object is created.
+ *
+ * @param propertyNames
+ * @param propertyValues
+ */
+ public HistoryRecord(String[] propertyNames, String[] propertyValues) {
+ this(propertyNames, propertyValues, new Date());
+ }
+
+ /**
+ * Constructs an entry containing multiple name-value pairs, where the names
+ * are taken from the defined structure.
+ *
+ * @param entryStructure
+ * @param propertyValues
+ * @param timestamp
+ */
+ public HistoryRecord(HistoryRecordStructure entryStructure, String[] propertyValues, Date timestamp) {
+ this(entryStructure.getPropertyNames(), propertyValues, timestamp);
+ }
+
+ /**
+ * Constructs an entry containing multiple name-value pairs, where the name is not
+ * unique.
+ *
+ * @param propertyNames
+ * @param propertyValues
+ * @param timestamp
+ */
+ public HistoryRecord(String[] propertyNames, String[] propertyValues, Date timestamp) {
+ Assert.assertNonNull(propertyNames, "The property names should be non-null.");
+ Assert.assertNonNull(propertyValues, "The property values should be non-null.");
+ Assert.assertNonNull(timestamp, "The timestamp should be non-null.");
+
+ Assert.assertTrue(propertyNames.length == propertyValues.length,
+ "The length of the property names and property values should be equal.");
+
+ this.propertyNames = propertyNames;
+ this.propertyValues = propertyValues;
+ this.timestamp = timestamp;
+ }
+
+ public String[] getPropertyNames() {
+ return this.propertyNames;
+ }
+
+ public String[] getPropertyValues() {
+ return this.propertyValues;
+ }
+
+ public Date getTimestamp() {
+ return this.timestamp;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/history/records/HistoryRecordStructure.java b/src/net/java/sip/communicator/service/history/records/HistoryRecordStructure.java
new file mode 100644
index 0000000..f115d04
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/records/HistoryRecordStructure.java
@@ -0,0 +1,76 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history.records;
+
+import net.java.sip.communicator.util.Assert;
+
+/**
+ * @author Alexander Pelov
+ */
+public class HistoryRecordStructure {
+
+ public static final TextType DEFAULT_TEXT_TYPE = TextType.LONG;
+
+ private String[] propertyNames;
+ private TextType[] valueTypes;
+
+ /**
+ * Creates an entry structure object used to define the shape of the data
+ * stored in the history. All valueTypes are set to TextType.LONG.
+ *
+ * Note that the property values are not unique, i.e. a single property
+ * may have 0, 1 or more values.
+ *
+ * @param propertyNames
+ */
+ public HistoryRecordStructure(String[] propertyNames) {
+ Assert.assertNonNull(propertyNames, "Parameter propertyNames should be non-null.");
+ this.propertyNames = new String[propertyNames.length];
+ System.arraycopy(propertyNames, 0, this.propertyNames, 0, this.propertyNames.length);
+
+ this.valueTypes = new TextType[this.propertyNames.length];
+ for(int i = 0; i < this.valueTypes.length; i++) {
+ this.valueTypes[i] = HistoryRecordStructure.DEFAULT_TEXT_TYPE;
+ }
+ }
+
+ /**
+ * Creates an entry structure object used to define the shape of the data
+ * stored in the history.
+ *
+ * Note that the property values are not unique, i.e. a single property
+ * may have 0, 1 or more values.
+ *
+ * @param propertyNames
+ * @param valueTypes
+ */
+ public HistoryRecordStructure(String[] propertyNames, TextType[] valueTypes) {
+ Assert.assertNonNull(propertyNames, "Parameter propertyNames should be non-null.");
+ Assert.assertNonNull(valueTypes, "Parameter valueTypes should be non-null.");
+ Assert.assertTrue(propertyNames.length == valueTypes.length,
+ "The length of the propertyNames and valueTypes should be equal.");
+
+ this.propertyNames = new String[propertyNames.length];
+ this.valueTypes = new TextType[valueTypes.length];
+
+ System.arraycopy(propertyNames, 0, this.propertyNames, 0, this.propertyNames.length);
+ System.arraycopy(valueTypes, 0, this.valueTypes, 0, this.valueTypes.length);
+ }
+
+ public String[] getPropertyNames() {
+ return this.propertyNames;
+ }
+
+ public TextType[] getValueTypes() {
+ return this.valueTypes;
+ }
+
+ public int getPropertyCount() {
+ return this.propertyNames.length;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/history/records/TextType.java b/src/net/java/sip/communicator/service/history/records/TextType.java
new file mode 100644
index 0000000..1cefb6d
--- /dev/null
+++ b/src/net/java/sip/communicator/service/history/records/TextType.java
@@ -0,0 +1,23 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.history.records;
+
+import net.java.sip.communicator.util.EnumerationBase;
+
+/**
+ * @author Alexander Pelov
+ */
+public final class TextType extends EnumerationBase {
+
+ public static final TextType SHORT = new TextType("SHORT");
+ public static final TextType LONG = new TextType("LONG");
+
+ protected TextType(String description) {
+ super(description);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/media/MediaService.java b/src/net/java/sip/communicator/service/media/MediaService.java
new file mode 100644
index 0000000..6ee1acb
--- /dev/null
+++ b/src/net/java/sip/communicator/service/media/MediaService.java
@@ -0,0 +1,86 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.media;
+
+import net.java.sip.communicator.service.media.event.MediaListener;
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The service is meant to be a wrapper of media libraries such as JMF,
+ * (J)FFMPEG, JMFPAPI, and others. It takes care of all media play and capture
+ * as well as media transport (e.g. over RTP).
+ *
+ * Before being able to use this service calles would have to make sure that
+ * it is initialized (i.e. consult the isInitialized() method).
+ * @author Emil Ivov
+ * @author Martin Andre
+ */
+public interface MediaService
+{
+ /**
+ * The method is meant for use by protocol service implementations when
+ * willing to send an invitation to a remote callee. It is at that point
+ * that the media service would open a port where it would be waiting for
+ * data coming from the specified call participant. Subsequent sdpoffers
+ * requested for the call that the original call participant belonged to,
+ * would receive, the same IP/port couple as the first one in order to allow
+ * conferencing. The associated port will be released once the call has
+ * ended.
+ *
+ * @param callParticipant the call participant meant to receive the offer
+ * @return a String containing an SDP offer.
+ */
+ public String generateSdpOffer(CallParticipant callParticipant);
+
+ /**
+ * The method is meant for use by protocol service implementations when
+ * willing to respond to an invitation received from a remote caller. It is
+ * at that point that the media service would open a port where it would
+ * wait for data coming from the specified call participant. Subsequent sdp
+ * offers/answers requested for the call that the original call participant
+ * belonged to will receive the same IP/port couple as the first one in
+ * order to allow conferencing. The associated port will be released once
+ * the call has ended.
+ *
+ * @param callParticipant the call participant meant to receive the answer
+ * @return a String containing an SDP answer.
+ */
+ public String generateSdpAnswer(CallParticipant callParticipant);
+
+ /**
+ * Adds a listener that will be listening for incoming media and changes
+ * in the state of the media listener
+ * @param listener the listener to register
+ */
+ public void addMediaListener(MediaListener listener);
+
+ /**
+ * Removes a listener that was listening for incoming media and changes
+ * in the state of the media listener
+ * @param listener the listener to remove
+ */
+ public void removeMediaListener(MediaListener listener);
+
+ /**
+ * Initializes the service implementation, and puts it in a state where it
+ * could interoperate with other services.
+ */
+ public void initialize();
+
+ /**
+ * Returns true if the media service implementation is initialized and ready
+ * for use by other services, and false otherwise.
+ */
+ public boolean isInitialized();
+
+ /**
+ * Makes the service implementation close all release any devices or other
+ * resources that it might have allocated and prepare for shutdown/garbage
+ * collection.
+ */
+ public void shutdown();
+}
diff --git a/src/net/java/sip/communicator/service/media/event/MediaEvent.java b/src/net/java/sip/communicator/service/media/event/MediaEvent.java
new file mode 100644
index 0000000..2993a46
--- /dev/null
+++ b/src/net/java/sip/communicator/service/media/event/MediaEvent.java
@@ -0,0 +1,24 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.media.event;
+
+import net.java.sip.communicator.service.protocol.CallParticipant;
+
+/**
+ *
+ * @author Martin Andre
+ */
+public class MediaEvent
+ extends java.util.EventObject
+{
+ CallParticipant callParticipant;
+
+ public MediaEvent(Object source)
+ {
+ super(source);
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/service/media/event/MediaListener.java b/src/net/java/sip/communicator/service/media/event/MediaListener.java
new file mode 100644
index 0000000..b1d8705
--- /dev/null
+++ b/src/net/java/sip/communicator/service/media/event/MediaListener.java
@@ -0,0 +1,19 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.media.event;
+
+/**
+ * Allows you to register for media events.
+ *
+ * @author Emil Ivov
+ */
+public interface MediaListener
+{
+ public void receivedMediaStream(MediaEvent evt);
+
+ public void mediaServiceStatusChanged();
+}
diff --git a/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java b/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java
new file mode 100644
index 0000000..9fe4c5a
--- /dev/null
+++ b/src/net/java/sip/communicator/service/msghistory/MessageHistoryService.java
@@ -0,0 +1,19 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.msghistory;
+
+import net.java.sip.communicator.service.history.HistoryReader;
+import net.java.sip.communicator.service.protocol.Contact;
+
+/**
+ * @author Alexander Pelov
+ */
+public interface MessageHistoryService extends HistoryReader {
+
+
+
+}
diff --git a/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java b/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java
new file mode 100644
index 0000000..11813ef
--- /dev/null
+++ b/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java
@@ -0,0 +1,75 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.netaddr;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+/**
+ * The NetworkAddressManagerService takes care of problems such as
+ * @author Emil Ivov
+ */
+public interface NetworkAddressManagerService
+{
+ /**
+ * Returns an InetAddress instance representing the local host or null if no
+ * IP address for the host could be found
+ * @return an InetAddress instance representing the local host or null if no
+ * IP address for the host could be found
+ */
+ public InetAddress getLocalHost();
+
+ /**
+ * Returns a localhostAddress. The method uses the following algorithm to
+ * choose among multiple addresses:
+ * if stun is enabled - queries STUN server and saves returned address
+ * Scans addresses for all network interfaces<br>
+ * if an address that matches the one returned by the STUN server is found - it is returned<br>
+ * else<br>
+ * if a non link local (starting with 172.16-31, 10, or 192.168) address is found it is returned<br>
+ * else<br>
+ * if a link local address is found it is returned<br>
+ * else<br>
+ * if the any address is accepted - it is returned<br>
+ * else<br>
+ * returns the InetAddress.getLocalHost()<br>
+ * if the InetAddress.getLocalHost() fails returns<br>
+ * the "any" local address - 0.0.0.0<br>
+ *
+ * @param anyAddressIsAccepted is 0.0.0.0 accepted as a return value.
+ * @return the address that was detected the address of the localhost.
+ */
+ public InetAddress getLocalHost(boolean anyAddressIsAccepted);
+
+ /**
+ * Tries to obtain a mapped/public address for the specified port. If the
+ * STUN lib fails, tries to retrieve localhost, if that fails too, returns
+ * null.
+ *
+ * @param port the port whose mapping we are interested in.
+ * @return a public address corresponding to the specified port or null if
+ * all attempts to retrieve such an address have failed.
+ */
+ public InetSocketAddress getPublicAddressFor(int port);
+
+ /**
+ * Initializes the network address manager service implementation and
+ * starts all processes/threads associated with this address manager, such
+ * as a stun firewall/nat detector, keep alive threads, binding lifetime
+ * discovery threads and etc. The method may also be used after a call to
+ * stop() as a reinitialization technique.
+ */
+ public void start();
+
+ /**
+ * Kills all threads/processes lauched by this thread and prepares it for
+ * shutdown. You may use this method as a reinitialization technique (
+ * you'll have to call start afterwards)
+ */
+ public void stop();
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/AuthorizationHandler.java b/src/net/java/sip/communicator/service/protocol/AuthorizationHandler.java
new file mode 100644
index 0000000..384d5d7
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/AuthorizationHandler.java
@@ -0,0 +1,18 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * @todo say that this is not a listener because methods have to have a return
+ * value
+ *
+ * @author Emil Ivov
+ */
+public interface AuthorizationHandler
+{
+ public void handleAuthorisationRequest();
+}
diff --git a/src/net/java/sip/communicator/service/protocol/Call.java b/src/net/java/sip/communicator/service/protocol/Call.java
new file mode 100644
index 0000000..5bf1916
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/Call.java
@@ -0,0 +1,96 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import java.util.*;
+import net.java.sip.communicator.service.protocol.event.CallChangeListener;
+
+
+/**
+ * A represenation of a Call. The Call class must obly be created by users (i.e.
+ * telephony protocols) of the PhoneUIService such as a SIP protocol
+ * implemenation. Extensions of this class might have names like SipCall
+ * or H323Call or AnyOtherTelephonyProtocolCall
+ *
+ * @author Emil Ivov
+ */
+public abstract class Call
+{
+ private String callID = null;
+ private CallParticipant callCreator = null;
+ private Vector callParticipants = new Vector();
+ private Vector callListeners = new Vector();
+
+ /**
+ * Creates a new call with the specified id.
+ * @param callID the id of the call to create.
+ */
+ protected Call(String callID, CallParticipant callCreator)
+ {
+ this.callID = callID;
+ }
+
+ /**
+ * Returns the id of the specified Call.
+ * @return String
+ */
+ public String getCallID()
+ {
+ return callID;
+ }
+
+ /**
+ * Compares the specified object with this call and returns true if it the
+ * specified object is an instance of a Call object and if the
+ * extending telephony protocol considers the calls represented by both
+ * objects to be the same.
+ *
+ * @param obj the call to compare this one with.
+ * @return true in case both objects are pertaining to the same call and
+ * false otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(obj == null
+ || !(obj instanceof Call))
+ return false;
+ if (obj == this
+ || ((Call)obj).getCallID().equals( getCallID() ))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Returns the call participant that created the call.
+ * @return a CallParticipant instance containing the call participant that
+ * created the call.
+ */
+ public CallParticipant getCallCreator()
+ {
+ return callCreator;
+ }
+
+ /**
+ * Returns an iterator over all call participants.
+ * @return an Iterator over all participants currently involved in the call.
+ */
+ public Iterator getCallParticipants()
+ {
+ return callParticipants.iterator();
+ }
+
+ /**
+ * Adds a call change listener to this call so that it could receive events
+ * on new call participants, theme changes and others.
+ * @param listener the listener to register
+ */
+ public void addCallChangeListener(CallChangeListener listener)
+ {
+
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/CallParticipant.java b/src/net/java/sip/communicator/service/protocol/CallParticipant.java
new file mode 100644
index 0000000..5d5e827
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/CallParticipant.java
@@ -0,0 +1,118 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import java.util.*;
+import net.java.sip.communicator.service.protocol.event.CallParticipantListener;
+
+import net.java.sip.communicator.service.gui.*;
+
+/**
+ * The CallParticipant is an interface that represents participants in a call.
+ * Users of the PhoneUIService need to implement this interface (or one of its
+ * default implementations such DefaultCallParticipant) in order to be able to
+ * register call participant in the user interface.
+ *
+ * <p>For SIP calls for example, it would be necessary to create a
+ * SipCallParticipant class that would provide sip specific implementations of
+ * various methods (getAddress() for example would return the participant's sip
+ * URI).
+ *
+ * @author Emil Ivov
+ */
+public interface CallParticipant
+{
+
+ /**
+ * Returns a unique identifier representing this participant. Identifiers
+ * returned by this method should remain unique across calls. In other
+ * words, if it returned the value of "A" for a given participant it should
+ * not return that same value for any other participant and return a
+ * different value even if the same person (address) is participating in
+ * another call. Values need not remain unique after restarting the program.
+ *
+ * @return an identifier representing this call participant.
+ */
+ public String getParticipantID();
+
+ /**
+ * Returns a reference to the call that this participant belongs to.
+ * @return a reference to the call containing this participant.
+ */
+ public Call getCall();
+
+ /**
+ * Returns a human readable name representing this participant.
+ * @return a String containing a name for that participant.
+ */
+ public String getDisplayName();
+
+ /**
+ * Returns a String locator for that participant. A locator might be a SIP
+ * URI, an IP address or a telephone number.
+ * @return the participant's address or phone number.
+ */
+ public String getAddress();
+
+ /**
+ * Returns an object representing the current state of that participant.
+ * CallParticipantState may vary among CONNECTING, RINGING, CALLING, BISY,
+ * CONNECTED, and others, and it reflects the state of the connection between
+ * us and that participant.
+ * @return a CallParticipantState instance representin the participant's
+ * state.
+ */
+ public CallParticipantState getState();
+
+ /**
+ * Determines whether or not this is the participant that originated the
+ * call (as opposed to the one that was called).
+ *
+ * @return true if this is the participant that calls us and falls if
+ * otherwise.
+ */
+ public boolean isCaller();
+
+ /**
+ * Allows the user interface to register a listener interested in changes
+ * @param listener a listener instance to register with this participant.
+ */
+ public void addCallParticipantListener(CallParticipantListener listener);
+
+ /**
+ * Unregisters the specified listener.
+ * @param listener the listener to unregister.
+ */
+ public void removeCallParticipantListener(CallParticipantListener listener);
+
+ /**
+ * Returns the date (time) when this call participant acquired its current
+ * status. This method is to be used by the phone ui interface in order
+ * to show the duration of a call.
+ * @return a java.util.Date object containing the date when this call
+ * participant entered its current state.
+ */
+ public Date getCurrentStateStartDate();
+
+ /**
+ * Returns a string representation of the participant in the form of
+ * <br>
+ * Display Name <address>;status=CallParticipantStatus
+ * @return a string representation of the participant and its state.
+ */
+ public String toString();
+
+ /**
+ * The method returns an image representation of the call participant (e.g.
+ * a photo). Generally, the image representation is acquired from the
+ * underlying telephony protocol and is transferred over the network during
+ * call negotiation.
+ * @return byte[] a byte array containing the image or null if no image is
+ * available.
+ */
+ public byte[] getImage();
+}
diff --git a/src/net/java/sip/communicator/service/protocol/CallParticipantState.java b/src/net/java/sip/communicator/service/protocol/CallParticipantState.java
new file mode 100644
index 0000000..b63a342
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/CallParticipantState.java
@@ -0,0 +1,234 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * The CallParticipantState class reflects the current state of a call
+ * participant. In other words when you start calling your grand mother she will
+ * be in a INITIATING_CALL state, when her phone rings her state will change to
+ * ALERTING_REMOTE_SIDE, and when she replies she will enter a CONNCECTED state.
+ *
+ * <p>Though not mandatory CallParticipantState would generally have one of the
+ * following life cycles
+ *
+ * <p> In the case with your grand mother that we just described we have:
+ * <br>INITIATING_CALL -> CONNECTING -> ALERTING_REMOTE_USER -> CONNECTED -> DISCONNECTED
+ *
+ * <p> If your granny was already on the phone we have:
+ * <br>INITIATING_CALL -> CONNECTING -> BUSY -> DISCONNECTED
+ *
+ * <p>Whenever someone tries to reach you:
+ * <br>INCOMING_CALL -> CONNECTED -> DISCONNECTED
+ *
+ * <p>A FAILED state is prone to appear at any place in the above diagram and is
+ * generally followed by a disconnected state.
+ *
+ * <p>Information on call participant is shonw in the phone user interface until
+ * they enter the DISCONNECTED state. At that point call participant information
+ * is automatically removed from the user interface and the call is considered
+ * terminated.
+ *
+ * @author Emil Ivov
+ */
+public class CallParticipantState
+{
+ /**
+ * This constant value indicates a String representation of the UNKNOWN
+ * call state.
+ * <br>This constant has the String value "Unknown".
+ */
+ public static final String _UNKNOWN = "Unknown";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is UNKNOWN - which means that there is no information on the state for
+ * the time being (this constant should be used as a default value for
+ * newly created call participant that don't yet have an attributed call
+ * state.
+ */
+ public static final CallParticipantState UNKNOWN =
+ new CallParticipantState(_UNKNOWN);
+
+ /**
+ * This constant value indicates a String representation of the
+ * INITIATING_CALL call state.
+ * <br>This constant has the String value "Initiating Call".
+ */
+ public static final String _INITIATING_CALL = "Initiating Call";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is INITIATING_CALL - which means that we're currently trying to open a
+ * socket and send our request. In the case of SIP for example we will leave
+ * this state the moment we receive a "100 Trying" request from a proxy or
+ * the remote side.
+ */
+ public static final CallParticipantState INITIATING_CALL =
+ new CallParticipantState(_INITIATING_CALL);
+
+ /**
+ * This constant value indicates a String representation of the CONNECTING
+ * call state.
+ * <br>This constant has the String value "Connecting".
+ */
+ public static final String _CONNECTING = "Connecting";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is CONNECTING - which means that a network connection to that participant
+ * is currently being established.
+ */
+ public static final CallParticipantState CONNECTING =
+ new CallParticipantState(_CONNECTING);
+
+ /**
+ * This constant value indicates a String representation of the
+ * ALERTING_REMOTE_SIDE call state.
+ * <br>This constant has the String value "Alerting Remote User".
+ */
+ public static final String _ALERTING_REMOTE_SIDE
+ = "Alerting Remote User (Ringing)";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is ALERTING_REMOTE_SIDE - which means that a network connection to that participant
+ * has been established and participant's phone is currently alerting the
+ * remote user of the current call.
+ */
+ public static final CallParticipantState ALERTING_REMOTE_SIDE =
+ new CallParticipantState(_ALERTING_REMOTE_SIDE);
+
+ /**
+ * This constant value indicates a String representation of the
+ * INCOMING_CALL call state.
+ * <br>This constant has the String value "Incoming Call".
+ */
+ public static final String _INCOMING_CALL = "Incoming Call";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is INCOMING_CALL - which means that the participant is willing to start
+ * a call with us. At that point local side should be playing a sound or a
+ * graphical alert (the phone is ringing).
+ */
+ public static final CallParticipantState INCOMING_CALL
+ = new CallParticipantState(_INCOMING_CALL);
+
+ /**
+ * This constant value indicates a String representation of the CONNECTED
+ * call state.
+ * <br>This constant has the String value "Connected".
+ */
+ public static final String _CONNECTED = "Connected";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is CONNECTED - which means that there is an ongoing call with that
+ * participant.
+ */
+ public static final CallParticipantState CONNECTED
+ = new CallParticipantState(_CONNECTED);
+
+ /**
+ * This constant value indicates a String representation of the DISCONNECTED
+ * call state.
+ * <br>This constant has the String value "Disconnected".
+ */
+ public static final String _DISCONNECTED = "Disconnected";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is DISCONNECTET - which means that this participant is not participating :)
+ * in the call any more.
+ */
+ public static final CallParticipantState DISCONNECTED =
+ new CallParticipantState(_DISCONNECTED);
+
+ /**
+ * This constant value indicates a String representation of the BUSY
+ * call state.
+ * <br>This constant has the String value "Busy".
+ */
+ public static final String _BUSY = "Busy";
+
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is BUSY - which means that an attempt to establish a call with that
+ * participant has been made and that it has been turned down by them (e.g.
+ * because they were already in a call).
+ */
+ public static final CallParticipantState BUSY
+ = new CallParticipantState(_BUSY);
+
+ /**
+ * This constant value indicates a String representation of the FAILED
+ * call state.
+ * <br>This constant has the String value "Failed".
+ */
+ public static final String _FAILED = "Failed";
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is ON_HOLD - which means that an attempt to establish a call with that
+ * participant has failed for an unexpected reason.
+ */
+ public static final CallParticipantState FAILED
+ = new CallParticipantState(_FAILED);
+
+ /**
+ * This constant value indicates a String representation of the ON_HOLD
+ * call state.
+ * <br>This constant has the String value "On Hold".
+ */
+ public static final String _ON_HOLD = "On Hold";
+ /**
+ * This constant value indicates that the state of the call participant is
+ * is ON_HOLD - which means that an attempt to establish a call with that
+ * participant has failed for an unexpected reason.
+ */
+ public static final CallParticipantState ON_HOLD
+ = new CallParticipantState(_ON_HOLD);
+
+ /**
+ * A string representationf this Participant Call State. Could be
+ * _CONNECTED, _FAILED, _CALLING and etc.
+ */
+ private String callStateStr;
+
+ /**
+ * Create a participant call state object with a value corresponding to the
+ * specified string.
+ * @param callParticipantState a string representation of the state.
+ */
+ private CallParticipantState(String callParticipantState)
+ {
+ this.callStateStr = callParticipantState;
+ }
+
+ /**
+ * Returns a String representation of tha CallParticipantSte.
+ *
+ * @return A string value (one of the _BUSY, _CALLING, _CONNECTED,
+ * _CONNECTING, _DISCONNECTED, _FAILED, _RINGING constants) representing
+ * this call participant state).
+ */
+ public String getStateString()
+ {
+ return callStateStr;
+ }
+
+ /**
+ * Returns a string represenation of this call state. Strings returned
+ * by this method have the following format:
+ * CallParticipantState:<STATE_STRING>
+ * and are meant to be used for loggin/debugging purposes.
+ * @return a string representation of this object.
+ */
+ public String toString()
+ {
+ return getClass().getName()+":"+getStateString();
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/Contact.java b/src/net/java/sip/communicator/service/protocol/Contact.java
new file mode 100644
index 0000000..10da17f
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/Contact.java
@@ -0,0 +1,72 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import java.util.*;
+
+/**
+ * This class represents the notion of a Contact or Buddy, that is widely used
+ * in instant messaging today. From a protocol point of view, a contact is
+ * generally considered to be another user of the service that proposes the
+ * protocol
+ *
+ *
+ * @author Emil Ivov
+ */
+public class Contact
+{
+ private String address = null;
+ private byte[] image = null;
+ private Hashtable contactProperties = new Hashtable();
+ private boolean isLocal = false;
+
+ public Contact(String address, boolean isLocal)
+ {
+ this.address = address;
+ this.isLocal = isLocal;
+ }
+
+ //address
+
+ public String getAddress()
+ {
+ return address;
+ }
+
+ public void setAddres(String address)
+ {
+ this.address = address;
+ }
+
+ //image
+ public byte[] getImage()
+ {
+ return image;
+ }
+
+ public void setImage(byte[] image)
+ {
+ this.image = image;
+ }
+
+ //properties
+ public void setProperty(String name, Object property)
+ {
+ contactProperties.put(name, property);
+ }
+
+ public Object getProperty(String name)
+ {
+ return contactProperties.get(name);
+ }
+
+ //islocal
+ public boolean isLocal()
+ {
+ return isLocal;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/ContactList.java b/src/net/java/sip/communicator/service/protocol/ContactList.java
new file mode 100644
index 0000000..c2964b9
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/ContactList.java
@@ -0,0 +1,22 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ *Contact lists would have to be modified by both a the user and the implementation
+ * of the service as the user interface might have to ask for the status of
+ * some particular users
+ *
+ * @author Emil Ivov
+ */
+public class ContactList
+{
+ public ContactList()
+ {
+ super();
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/DefaultCallParticipant.java b/src/net/java/sip/communicator/service/protocol/DefaultCallParticipant.java
new file mode 100644
index 0000000..dd2e2a0
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/DefaultCallParticipant.java
@@ -0,0 +1,342 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.service.protocol;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.event.*;
+
+
+/**
+ * The DefaultCallParticipant provides a default implementation for most of the
+ * CallParticpant methods with the purpose of only leaving custom protocol
+ * development to clients using the PhoneUI service.
+ * <p> </p>
+ *
+ * @author Emil Ivov
+ */
+public class DefaultCallParticipant
+ implements CallParticipant
+{
+
+ /**
+ * All the CallParticipant listeners registered with this CallParticipant.
+ */
+ protected ArrayList callParticipantListeners = new ArrayList();
+
+ /**
+ * The address (sip address, phone number or other protocol specific
+ * identifier) of this call participant.
+ */
+ protected String address = null;
+
+ /**
+ * The state of the call participant.
+ */
+ protected CallParticipantState callParticipantState =
+ CallParticipantState.UNKNOWN;
+ /**
+ * Indicates the date when this call participant passed into its current state.
+ */
+ protected Date currentStateStartDate = new Date();
+
+ /**
+ * A human readable name corresponding to the call participant.
+ * (e.g. John Travolta)
+ */
+ private String displayName = null;
+
+ /**
+ * A byte array containing the image/photo representing the call participant.
+ */
+ protected byte[] image;
+
+ /**
+ * A string provided by the underlying implementationm uniquely identifying
+ * the participant.
+ */
+ protected String participantID;
+
+ /**
+ * Specifies whether or not the participant is the one that initiated the
+ * call.
+ */
+ protected boolean isCaller = false;
+
+ /**
+ * Returns a String identifying the call that this participant belongs to.
+ * We have been thinking of returning an instance of a Call interface here
+ * but this would mean too much to implement for users of this service.
+ */
+ protected Call call;
+
+ /**
+ * @param listener a listener instance to register with this participant.
+ *
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public void addCallParticipantListener(CallParticipantListener listener)
+ {
+ this.callParticipantListeners.add(listener);
+ }
+
+ /**
+ * Unregisters the specified listener.
+ * @param listener the listener to unregister.
+ */
+ public void removeCallParticipantListener(CallParticipantListener listener)
+ {
+ if(listener == null)
+ return;
+ callParticipantListeners.remove(listener);
+ }
+
+ /**
+ * Returns a String locator for that participant.
+ *
+ * @return the participant's address or phone number.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public String getAddress()
+ {
+ return address;
+ }
+
+ /**
+ * Specifies the address, phone number, or other protocol specific
+ * identifier that represents this call participant. This method is to be
+ * used by service users and MUST NOT be called by the implementation.
+ *
+ * @param address The address of this call participant.
+ */
+ public void setAddress(String address)
+ {
+ String oldAddress = getAddress();
+ this.address = address;
+ //Fire the Event
+ fireCallParticipantChangeEvent(
+ new CallParticipantChangeEvent(
+ this,
+ CallParticipantChangeEvent.CALL_PARTICIPANT_ADDRESS_CHANGE,
+ oldAddress,
+ address
+ ));
+ }
+
+ /**
+ * Returns an object representing the current state of that participant.
+ *
+ * @return a CallParticipantState instance representin the participant's
+ * state.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public CallParticipantState getState()
+ {
+ return callParticipantState;
+ }
+
+ /**
+ * Causes this CallParticipant to enter the specified state. The method also
+ * sets the currentStateStartDate field and fires a
+ * CallParticipantChangeEvent.
+ *
+ * @param newState the state this call participant should enter.
+ */
+ public void enterState(CallParticipantState newState)
+ {
+ CallParticipantState oldState = getState();
+ this.callParticipantState = newState;
+ this.currentStateStartDate = new Date();
+ fireCallParticipantChangeEvent(
+ new CallParticipantChangeEvent(
+ this,
+ CallParticipantChangeEvent.CALL_PARTICIPANT_STATUS_CHANGE,
+ oldState,
+ newState));
+ }
+
+ /**
+ * Notifies all registered CallParticipantListener-s of the specified
+ * change event.
+ *
+ * @param evt the event to dispatch.
+ */
+ protected void fireCallParticipantChangeEvent(CallParticipantChangeEvent
+ evt)
+ {
+ for (int i = 0; i < callParticipantListeners.size(); i++)
+ {
+ ((CallParticipantListener)callParticipantListeners.get(i))
+ .participantChange(evt);
+ }
+ }
+
+ /**
+ * Returns the date (time) when this call participant acquired its
+ * current status.
+ *
+ * @return a java.util.Date object containing the date when this call
+ * participant entered its current state.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public Date getCurrentStateStartDate()
+ {
+ return currentStateStartDate;
+ }
+
+ /**
+ * Returns a human readable name representing this participant.
+ *
+ * @return a String containing a name for that participant.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public String getDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Sets a human readable name representing this participant.
+ *
+ * @param displayName the participant's display name
+ */
+ public void setDisplayName(String displayName)
+ {
+ String oldName = getDisplayName();
+ this.displayName = displayName;
+
+ //Fire the Event
+ fireCallParticipantChangeEvent(
+ new CallParticipantChangeEvent(
+ this,
+ CallParticipantChangeEvent.CALL_PARTICIPANT_DISPLAY_NAME_CHANGE,
+ oldName,
+ displayName
+ ));
+ }
+
+ /**
+ * The method returns an image representation of the call participant
+ * (e.g.
+ *
+ * @return byte[] a byte array containing the image or null if no image
+ * is available.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public byte[] getImage()
+ {
+ return image;
+ }
+
+ /**
+ * Sets the byte array containing an image representation (photo or picture)
+ * of the call participant.
+ *
+ * @param image a byte array containing the image
+ */
+ public void setImage(byte[] image)
+ {
+ byte[] oldImage = getImage();
+ this.image = image;
+
+ //Fire the Event
+ fireCallParticipantChangeEvent(
+ new CallParticipantChangeEvent(
+ this,
+ CallParticipantChangeEvent.CALL_PARTICIPANT_IMAGE_CHANGE,
+ oldImage,
+ image
+ ));
+ }
+
+ /**
+ * Returns a unique identifier representing this participant.
+ *
+ * @return an identifier representing this call participant.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public String getParticipantID()
+ {
+ return participantID;
+ }
+
+ /**
+ * Sets the String that serves as a unique identifier of this
+ * CallParticipant.
+ * @param participantID the ID of this call participant.
+ */
+ public void setParticipantID(String participantID)
+ {
+ this.participantID = participantID;
+ }
+
+ /**
+ * Sets this call participant to be (or not) the one that initiated the
+ * current call.
+ * @param isCaller a bool specifying whether or not the participant is a
+ * caller.
+ */
+ public void setIsCaller(boolean isCaller)
+ {
+ this.isCaller = isCaller;
+ }
+
+ /**
+ * Determines whether or not this is the participant that originated the
+ * call (as opposed to the one that was called).
+ *
+ * @return true if this is the participant that calls us and falls if
+ * otherwise.
+ * @todo Implement this
+ * net.java.sip.communicator.service.phoneui.CallParticipant method
+ */
+ public boolean isCaller()
+ {
+ return isCaller;
+ }
+
+ /**
+ * Returns a reference to the call that this participant belongs to. Calls
+ * are created by underlying telephony protocol implementations.
+ *
+ * @return a reference to the call containing this participant.
+ */
+ public Call getCall()
+ {
+ return call;
+ }
+
+ /**
+ * Sets the call containing this participant.
+ * @param call the call that this call participant is
+ * partdicipating in.
+ */
+ public void setCall(Call call)
+ {
+ this.call = call;
+ }
+
+ /**
+ * Returns a string representation of the participant in the form of
+ * <br>
+ * Display Name <address>;status=CallParticipantStatus
+ * @return a string representation of the participant and its state.
+ */
+ public String toString()
+ {
+ return getDisplayName() + " <" + getAddress()
+ + ">;status=" + getState().getStateString();
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationNotSupportedException.java b/src/net/java/sip/communicator/service/protocol/OperationNotSupportedException.java
new file mode 100644
index 0000000..135d61a
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationNotSupportedException.java
@@ -0,0 +1,30 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * The OperationNotSupportedException is used by telephony providers as an
+ * indication that a requested operation is not supported or implemented.
+ *
+ * @author Emil Ivov
+ */
+public class OperationNotSupportedException
+ extends Exception
+{
+ /**
+ * Creates an OperationNotSupportedException instance with the specified
+ * reason phrase.
+ * @param message a detailed message explaining any particular details as
+ * to why is not the specified operation supported or null if no particular
+ * details exist.
+ */
+ public OperationNotSupportedException(String message)
+ {
+ super(message);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSet.java b/src/net/java/sip/communicator/service/protocol/OperationSet.java
new file mode 100644
index 0000000..7f5cb5a
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSet.java
@@ -0,0 +1,15 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * @author Emil Ivov
+ */
+public interface OperationSet
+{
+ public String getOperationSetName();
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetBasicInstantMessaging.java b/src/net/java/sip/communicator/service/protocol/OperationSetBasicInstantMessaging.java
new file mode 100644
index 0000000..6f26752
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetBasicInstantMessaging.java
@@ -0,0 +1,22 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public interface OperationSetBasicInstantMessaging
+ extends OperationSet
+{
+ public void createMessageFactory();
+
+ public void sendInstantMessage();
+
+ public void addMessageListener();
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java b/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java
new file mode 100644
index 0000000..3560e52
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java
@@ -0,0 +1,87 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import net.java.sip.communicator.service.protocol.event.CallListener;
+
+
+
+/**
+ * An Operation Set defining all basic telephony operations such as conducting
+ * simple calls and etc. Note that video is not considered as a part of a
+ * supplementary operation set and if included in the service should be available
+ * behind the basic telephoy set.
+ *
+ * @author Emil Ivov
+ */
+public interface OperationSetBasicTelephony
+ extends OperationSet
+{
+ /**
+ * Registers the specified CallListener with this provider so that it could
+ * be notified when incoming calls are received. This method is called
+ * by the implementation of the PhoneUI service.
+ * @param listener the listener to register with this provider.
+ */
+ public void addCallListener(CallListener listener);
+
+ /**
+ * Removes the specified listener from the list of call listeners.
+ * @param listener the listener to unregister.
+ */
+ public void removeCallListener(CallListener listener);
+
+
+ /**
+ * Create a new call and invite the specified CallParticipant to it.
+ * @param uri the address of the callee that we should invite to a new
+ * call.
+ * @return CallParticipant the CallParticipant that will represented by the
+ * specified uri. All following state change events will be delivered
+ * through that call participant. The Call that this participant is a member
+ * of could be retrieved from the CallParticipatn instance with the use
+ * of the corresponding method.
+ */
+ public Call createCall(String uri);
+
+ /**
+ * Indicates a user request to answer an incoming call from the specified
+ * CallParticipant.
+ * @param participant the call participant that we'd like to anwer.
+ */
+ public void answerCallParticipant(CallParticipant participant);
+
+ /**
+ * Puts the specified CallParticipant "on hold". In other words incoming
+ * media flows are not played and outgoing media flows are either muted or
+ * stopped, without actually interrupting the session.
+ * @param participant the participant that we'd like to put on hold.
+ */
+ public void putOnHold(CallParticipant participant);
+
+ /**
+ * Resumes communication with a call participant previously put on hold. If
+ * the specified participant is not "On Hold" at the time putOffHold is
+ * called, the method has no effect.
+ * @param participant the call participant to put on hold.
+ */
+ public void putOffHold(CallParticipant participant);
+
+ /**
+ * Indicates a user request to end a call with the specified call
+ * particiapnt.
+ * @param participant the participant that we'd like to hang up on.
+ */
+ public void hangupCallParticipant(CallParticipant participant);
+
+ /**
+ * Returns an iterator over all currently active calls.
+ * @return Iterator
+ */
+ public java.util.Iterator getActiveCalls();
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetCallTransfer.java b/src/net/java/sip/communicator/service/protocol/OperationSetCallTransfer.java
new file mode 100644
index 0000000..fcba14d
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetCallTransfer.java
@@ -0,0 +1,27 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * An Operation Set defining operations that allow transfering calls to a new
+ * location.
+ *
+ * @author Emil Ivov
+ */
+public interface OperationSetCallTransfer
+ extends OperationSet
+{
+ /**
+ * Indicates a user request to transfer the specified call particiapant to a
+ * new (target) uri.
+ * @param participant the call participant we'd like to transfer
+ * @param targetURI the uri that we'd like this call participant to be
+ * transferred to.
+ */
+ public void transferCallParticipant(CallParticipant participant,
+ String targetURI);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java b/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java
new file mode 100644
index 0000000..8d06a87
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java
@@ -0,0 +1,25 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import net.java.sip.communicator.service.protocol.event.FileListener;
+
+/**
+ * The File Transfer Operation Set provides an interface towards those functions
+ * of a given protocl, that allow transferring files among users.
+ *
+ * @todo say that meta contacts must be implemented by the user interface
+ *
+ * @author Emil Ivov
+ */
+public interface OperationSetFileTransfer
+ extends OperationSet
+{
+ public void sendFile();
+
+ public void addFileListener(FileListener listener);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetPresence.java b/src/net/java/sip/communicator/service/protocol/OperationSetPresence.java
new file mode 100644
index 0000000..b46228f
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetPresence.java
@@ -0,0 +1,37 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import net.java.sip.communicator.service.protocol.event.PresenceStatusListener;
+
+/**
+ * @todo Say that ContactList management and Presence functions
+ * @todo Say that presence implementations should not contain any persistant
+ * data on contactlists and who they should be keeping records of
+ *
+ * @author Emil Ivov
+ */
+public interface OperationSetPresence
+ extends OperationSet
+{
+ public ContactList retrieveContactList();
+
+ public void addPresenceStatusListener(PresenceStatusListener listener);
+
+ public PresenceStatus getStatusForContact();
+
+ /**
+ * Some protos support batch status requests. We should therefore give them
+ * the possibility to execute them instead of demanding status one by one
+ * @param list ContactList
+ */
+ public void addPresenceStatusSubscriptions(ContactList list);
+
+
+ public void setAuthorizationHandler(AuthorizationHandler handler);
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetTelephonyConferencing.java b/src/net/java/sip/communicator/service/protocol/OperationSetTelephonyConferencing.java
new file mode 100644
index 0000000..130bf80
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetTelephonyConferencing.java
@@ -0,0 +1,47 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * Provides operations necessary to create and handle conferencing calls. This
+ * interface does
+ *
+ * @author Emil Ivov
+ */
+public interface OperationSetTelephonyConferencing
+ extends OperationSet
+{
+ /**
+ * Creates a conference call with the specified callees as call
+ * participants.
+ *
+ * @param callees the list of addresses that we should call
+ * @return the newly created conference call containing all CallParticipants
+ * @throws OperationNotSupportedException if the provider does not have any
+ * conferencing features.
+ */
+ public Call createConfCall(String[] callees)
+ throws OperationNotSupportedException;
+
+ /**
+ * Invitites the callee represented by the specified uri to an already
+ * existing call. The difference between this method and createConfCall is
+ * that inviteCalleeToCall allows a user to transform an existing 1 to 1
+ * call into a conference call, or add new participants to an already
+ * established conference.
+ *
+ * @param uri the callee to invite to an existing conf call.
+ * @param existingCall the call that we should invite the callee to.
+ * @return the CallParticipant object corresponding to the callee
+ * represented by the specified uri.
+ * @throws OperationNotSupportedException if allowing additional callees to
+ * a pre-established call is not supported.
+ */
+ public CallParticipant inviteCalleeToCall(String uri, Call existingCall)
+ throws OperationNotSupportedException;
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/PresenceStatus.java b/src/net/java/sip/communicator/service/protocol/PresenceStatus.java
new file mode 100644
index 0000000..d20305a
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/PresenceStatus.java
@@ -0,0 +1,135 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * The class is used to represent the state of the connection
+ * of a given ProtocolProvider or Contact. It is up to the implementation to
+ * determine the exact states that an object might go through. An IM provider
+ * for example might go through states like, CONNECTING, ON-LINE, AWAY, etc, A
+ * status instance is represented by an integer varying from 0 to
+ * 100, a Status Name and a Status Description.
+ *
+ * The integer status variable is used so that the users of the service get the
+ * notion of whether or not a given Status instance represents a state that
+ * allows communication (above 20) and so that it could compare instances
+ * between themselves (e.g. for sorting a ContactList for example).
+ *
+ * A state may not be created by the user. User may request a status change
+ * giving parameters requested by the ProtocolProvider. Once a statue is
+ * successfully entered by the provider, a ConnectivityStatus instacne is
+ * conveyed to the user through a notification event.
+ *
+ * @author Emil Ivov
+ */
+public class PresenceStatus
+ implements Comparable
+{
+
+ /**
+ * Represents the connectivity status on a scale from
+ * 0 to 100 with 0 indicating complete disabiilty for communication and 100
+ * maximum ability and user willingness. Implementors of this service should
+ * respect the following indications for status values.
+ * 0 - complete disability
+ * 1:10 - initializing.
+ * 1:20 - trying to enter a state where communication is possible (Connecting ..)
+ * 20:50 - communication is possible but might be unwanted, inefficient or delayed(e.g. Away state in IM clients)
+ * 50:80 - communication is possible (On - line)
+ * 80:100 - communication is possible and user is eager to communicate. (Free for chat! Talk to me, etc.)
+ */
+ protected short status = 0;
+
+ /**
+ * The name of this status instance (e.g. Away, On-line, Invisible, etc.)
+ */
+ protected String statusName = null;
+
+ /**
+ * A message describing this status instance (e.g. I am busy right now, and
+ * I'll get back to you later).
+ */
+ protected String statusMessage = null;
+
+ /**
+ * Creates an instance of this class using the specified parameters.
+ * @param status the status variable representing the new instance
+ * @param statusName the name of this PresenceStatus
+ * @param statusMessage a message describing the user's status.
+ */
+ protected PresenceStatus(short status, String statusName, String statusMessage)
+ {
+ this.status = status;
+ this.statusName = statusName;
+ this.statusMessage = statusMessage;
+ }
+
+
+ /**
+ * Returns an integer representing the presence status on a scale from
+ * 0 to 100.
+ * @return a short indicating the level of availability corresponding to
+ * this status object.
+ */
+ public short getStatus()
+ {
+ return status;
+ }
+
+ /**
+ * Returns the name of this status (such as Away, On-line, Invisible, etc).
+ * @return a String variable containing the name of this status instance.
+ */
+ public String getStatusName()
+ {
+ return statusName;
+ }
+
+ /**
+ * Returns a description of the status (like for example a note giving
+ * details on that status like "out for a piss" for example).
+ * @return a String variable detailing the status.
+ */
+ public String getStatusMessage()
+ {
+ return statusMessage;
+ }
+
+ /**
+ * Returns a string represenation of this provider status. Strings returned
+ * by this method have the following format: PresenceStatus:<STATUS_STRING>:
+ * <STATUS_MESSAGE> and are meant to be used for loggin/debugging purposes.
+ * @return a string representation of this object.
+ */
+ public String toString()
+ {
+ return getClass().getName()
+ + ":" + getStatusName()
+ + ":" + getStatusMessage();
+ }
+
+ /**
+ * Compares this inatance with the specified object for order. Returns a
+ * negative integer, zero, or a positive integer as this status instance is
+ * considered to represent less, as much, or more availabilite than the one
+ * specified by the parameter.<p>
+ *
+ * @param o the Object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ *
+ * @throws ClassCastException if the specified object's type prevents it
+ * from being compared to this Object.
+ * @throws NullPointerException if o is null
+ */
+ public int compareTo(Object o)
+ throws ClassCastException, NullPointerException
+ {
+ PresenceStatus target = (PresenceStatus)o;
+ return (getStatus() - target.getStatus());
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java b/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java
new file mode 100644
index 0000000..69b6759
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java
@@ -0,0 +1,178 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import net.java.sip.communicator.service.protocol.event.*;
+import java.util.*;
+
+
+/**
+ * The ProtocolProvider interface should be implemented by bundles that wrap telephony
+ * protocol stacks. It gives the user interface a way to plug into those stacks
+ * and receive notifications on status change and incoming calls, as well as
+ * deliver user requests for establishing or ending calls, putting participants
+ * on hold and etc.
+ *
+ * @author Emil Ivov
+ */
+public interface ProtocolProviderService
+{
+
+
+ /**
+ * Returns a String containing a human readable string representation of the
+ * provider. Such names would be shown by a telephony user interface so that
+ * users may chose the protocol they'd like to use to make a specific call.
+ * Most often this would be the name of the protocol the provider
+ * implements, and/or some combination of the server it is attached to and
+ * the user name used. It is up to providers to make sure that th.
+ * @return a String representation of this provider.
+ */
+ public String getProviderName();
+
+ /**
+ * Returns the short name of the protocol that the implementation of this
+ * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
+ * example).
+ * @return a String containing the short name of the protocol this service
+ * is taking care of.
+ */
+ public String getProtocolName();
+
+ /**
+ * Many communications protocols have well known logos that users are
+ * familiar with. The image returned by this method should have a 32x32 size
+ * and if this is not the case the user interface will try to resize it
+ * (results are not guaranteed). In case the Provider does not wish to use
+ * this feature, this method should return null. In that case the user
+ * interface may try to show an image representation that it finds suitable
+ * (or just a common protocol logo).
+ * @return byte[] a 32x32 protocol logo or representative image.
+ */
+ public byte[] getProviderImage();
+
+ /**
+ * Registers the specified listener with this provider so that it would
+ * receive notifications on changes of its state or other properties such
+ * as its local address and display name.
+ * @param listener the listener to register.
+ */
+ public void addProviderChangeListener(ProviderChangeListener listener);
+
+ /**
+ * Removes the specified listener.
+ * @param listener the listener to remove.
+ */
+ public void removeProviderChangeListener(ProviderChangeListener listener);
+
+ /**
+ * Returns the protocol specific contact instance representing the local
+ * user. In the case of SIP this would be your local sip address or in the
+ * case of an IM protocol such as ICQ - your own uin. No set method should
+ * be provided in implementations of this class. The getLocalContact()
+ * method is only used for giving information to the user on their currently
+ * used addressed a different service (ConfigurationService) should be used
+ * for changing that kind of settings.
+ * @return the Contact (address, phone number, or uin) that the Provider
+ * implementation is communicating on behalf of.
+ */
+ public Contact getLocalContact();
+
+ /**
+ * Returns a PresenceStatus instance representing the state this provider is
+ * currently in. Note that PresenceStatus instances returned by this method
+ * MUST adequately represent all possible states that a provider might
+ * enter duruing its lifecycle, includindg those that would not be visible
+ * to others (e.g. Initializing, Connecting, etc ..) and those that will be
+ * sent to contacts/buddies (On-Line, Eager to chat, etc.).
+ * @return PresenceStatus
+ */
+ public PresenceStatus getStatus();
+
+ /**
+ * Requests the provider to enter into a status corresponding to the
+ * specified paramters. Note that calling this method does not necessarily
+ * imply that the requested status would be entered. This method would
+ * return right after being called and the caller should add itself as
+ * a listener to this class in order to get notified when the state has
+ * actually changed.
+ *
+ * @param status the PresenceStatus as returned by getRequestableStatusSet
+ * @param statusMessage the message that should be set as the reason to
+ * enter that status
+ * @throws IllegalArgumentException if the status requested is not a valid
+ * PresenceStatus supported by this provider.
+ */
+ public void enterStatus(PresenceStatus status, String statusMessage)
+ throws IllegalArgumentException;
+
+ /**
+ * Returns the set of PresenceStatus objects that a user of this service
+ * may request the provider to enter. Note that the provider would most
+ * probaby enter more states than those returned by this method as they
+ * only depict instances that users may request to enter. (e.g. a user
+ * may not request a "Connecting..." state - it is a temporary state
+ * that the provider enters while trying to enter the "Connected" state).
+ *
+ * @return Iterator a PresenceStatus array containing "enterable"
+ * status instances.
+ */
+ public Iterator getRequestableStatusSet();
+
+ /**
+ * Returns a string representation of the registration service that is
+ * used by this provider or null if none is used. The string returned by
+ * this method is used by the user interface so that it could give (if
+ * necessary) information to the user on its point of registration. It is
+ * therefore not necessary to return a valid URL but rather a human readable
+ * descriptive string.
+ * @return a string representing (the address of) the service being used.
+ */
+ public String getRegistrationServer();
+
+ /**
+ * Allows the user interface to plugin an object that would handle incoming
+ * authentication challenges.
+ * @param authority SecurityAuthority
+ */
+ public void setSecurityAuthority(SecurityAuthority authority);
+
+ /**
+ * Returns an array containing all operation sets supported by the current
+ * implementation. When querying this method users must be prepared to
+ * receive any sybset of the OperationSet-s defined by this service. They
+ * MUST ignore any OperationSet-s that they are not aware of and that may be
+ * defined by future version of this service. Such "unknown" OperationSet-s
+ * though not encouraged, may also be defined by service implementors.
+ *
+ * @return an array of OperationSet-s supported by this protocol provider
+ * implementation.
+ */
+ public OperationSet[] getSupportedOperationSets();
+
+ /**
+ * Initialized the service implementation, and puts it in a sate where it
+ * could interoperate with other services.
+ */
+ public void initialize();
+
+ /**
+ * Returns true if the provider service implementation is initialized and ready
+ * for use by other services, and false otherwise. Note that this should
+ * remain as a separate method and not be one of the presence statuses
+ * since, in theorry, an implementation might very well be unaware of
+ * its presence status while uninitialized.
+ */
+ public boolean isInitialized();
+
+ /**
+ * Makes the service implementation close all open sockets and release
+ * any resources that it might have taken and prepare for shutdown/garbage
+ * collection.
+ */
+ public void shutdown();
+}
diff --git a/src/net/java/sip/communicator/service/protocol/SecurityAuthority.java b/src/net/java/sip/communicator/service/protocol/SecurityAuthority.java
new file mode 100644
index 0000000..488e1bf
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/SecurityAuthority.java
@@ -0,0 +1,17 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * Allows the user interface
+ *
+ * @author Emil Ivov
+ */
+public interface SecurityAuthority
+{
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/CallChangeListener.java b/src/net/java/sip/communicator/service/protocol/event/CallChangeListener.java
new file mode 100644
index 0000000..cb5cf2b
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/CallChangeListener.java
@@ -0,0 +1,19 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+/**
+ * Allows notification for new call participants, theme changes and
+ * other call state events.
+ * @author Emil Ivov
+ */
+public class CallChangeListener
+ implements EventListener
+{
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/CallListener.java b/src/net/java/sip/communicator/service/protocol/event/CallListener.java
new file mode 100644
index 0000000..84a18d6
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/CallListener.java
@@ -0,0 +1,29 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+
+/**
+ * Instances of this class are used for listening for notifications coming out
+ * of a telephony Provider - such as an incoming Call for example. Whenever
+ * a telephony Provider receives an invitation to a call from a particular
+ *
+ * @author Emil Ivov
+ */
+public interface CallListener extends EventListener
+{
+ /**
+ * This method is called by a protocol provider whenever an incoming call
+ * is received.
+ * @param event a CallReceivedEvent instance describing the new incoming
+ * call
+ */
+ public void incomingCallReceived(CallReceivedEvent event);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/CallParticipantChangeEvent.java b/src/net/java/sip/communicator/service/protocol/event/CallParticipantChangeEvent.java
new file mode 100644
index 0000000..5817d56
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/CallParticipantChangeEvent.java
@@ -0,0 +1,84 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import net.java.sip.communicator.service.protocol.CallParticipant;
+
+/**
+ * CallParticipantChangeEvent-s are triggerred whenever a change occurs in a
+ * CallParticipant. Dispatched events may be of one of the following types.
+ * <p>
+ * CALL_PARTICIPANT_STATUS_CHANGE - indicates a change in the status of the
+ * participant.
+ * <p>
+ * CALL_PARTICIPANT_DISPLAY_NAME_CHANGE - means that participant's displayName
+ * has changed
+ * <p>
+ * CALL_PARTICIPANT_ADDRESS_CHANGE - means that participant's address has changed.
+ * <p>
+ * CALL_PARTICIPANT_IMAGE_CHANGE - participant update photo.
+ * <p>
+ *
+ * @author Emil Ivov
+ */
+public class CallParticipantChangeEvent
+ extends java.beans.PropertyChangeEvent
+{
+ /**
+ * An event type indicating that the corresponding event is caused by a
+ * change of the CallParticipant's status.
+ */
+ public static final String CALL_PARTICIPANT_STATUS_CHANGE =
+ "CallParticipantStatusChange";
+
+ /**
+ * An event type indicating that the corresponding event is caused by a
+ * change of the participant's display name.
+ */
+ public static final String CALL_PARTICIPANT_DISPLAY_NAME_CHANGE =
+ "CallParticipantDisplayNameChange";
+
+ /**
+ * An event type indicating that the corresponding event is caused by a
+ * change of the participant's address.
+ */
+ public static final String CALL_PARTICIPANT_ADDRESS_CHANGE =
+ "CallParticipantAddressChange";
+
+ /**
+ * An event type indicating that the corresponding event is caused by a
+ * change of the participant's photo/picture.
+ */
+ public static final String CALL_PARTICIPANT_IMAGE_CHANGE =
+ "CallParticipantImageChange";
+
+ /**
+ * Creates a CallParticipantChangeEvent with the specified source, type,
+ * oldValue and newValue.
+ * @param source the participant that produced the event.
+ * @param type the type of the event (i.e. address change, state change etc.).
+ * @param oldValue the value of the changed property before the event occurred
+ * @param newValue current value of the changed property.
+ */
+ public CallParticipantChangeEvent(CallParticipant source, String type,
+ Object oldValue, Object newValue)
+ {
+ super(source, type, oldValue, newValue);
+ }
+
+ /**
+ * Returns the type of this event.
+ * @return a string containing one of the following values:
+ * CALL_PARTICIPANT_STATUS_CHANGE, CALL_PARTICIPANT_DISPLAY_NAME_CHANGE,
+ * CALL_PARTICIPANT_ADDRESS_CHANGE, CALL_PARTICIPANT_IMAGE_CHANGE
+ */
+ public String getEventType()
+ {
+ return getPropertyName();
+ }
+}
+
diff --git a/src/net/java/sip/communicator/service/protocol/event/CallParticipantControlEvent.java b/src/net/java/sip/communicator/service/protocol/event/CallParticipantControlEvent.java
new file mode 100644
index 0000000..86f0aa3
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/CallParticipantControlEvent.java
@@ -0,0 +1,62 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The CallParticipantControlEvent is issued by the PhoneUIService as a result
+ * of a user request to modify the way a CallParticipant is associated with a
+ * call, or in other words "Answer" the incoming call of a CallParticipant or
+ * "Hangup" and thus and the participation of a CallParticipant in a call. The
+ * source of the event is considered to be the CallParticipant that is being
+ * controlled. As the event might also be used to indicate a user request to
+ * transfer a given participant to a different number, the calss also contains
+ * a targetURI field, containing the adress that a client is being redirected to
+ * (the target uri might also have slightly different meanings depending on the
+ * method dispatching the event).
+ * @author Emil Ivov
+ *
+ */
+public class CallParticipantControlEvent
+ extends java.util.EventObject
+{
+ private String targetURI = null;
+
+ /**
+ * Creates a new event instance with the specifieed source CallParticipant
+ * and targetURI, if any.
+ * @param source the CallParticipant that this event is pertaining to.
+ * @param targetURI the URI to transfer to if this is a "Transfer" event
+ * or null otherwise.
+ */
+ public CallParticipantControlEvent(CallParticipant source, String targetURI)
+ {
+ super(source);
+ this.targetURI = targetURI;
+ }
+
+ /**
+ * Returns the CallParticipant that this event is pertaining to.
+ * @return the CallParticipant that this event is pertaining to.
+ */
+ public CallParticipant getAssociatedCallparticipant()
+ {
+ return (CallParticipant) source;
+ }
+
+ /**
+ * Returns the target URI if this is event is triggered by a transfer
+ * request or null if not.
+ * @return null or a tranfer URI.
+ */
+ public String getTargetURI(){
+ return targetURI;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/CallParticipantListener.java b/src/net/java/sip/communicator/service/protocol/event/CallParticipantListener.java
new file mode 100644
index 0000000..ceb90b1
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/CallParticipantListener.java
@@ -0,0 +1,19 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+
+/**
+ * @author Emil Ivov
+ */
+public interface CallParticipantListener
+ extends EventListener
+{
+ public void participantChange(CallParticipantChangeEvent evt);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/CallReceivedEvent.java b/src/net/java/sip/communicator/service/protocol/event/CallReceivedEvent.java
new file mode 100644
index 0000000..8cae0b3
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/CallReceivedEvent.java
@@ -0,0 +1,37 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * A class representing the event of a call reception.
+ * @author Emil Ivov
+ */
+public class CallReceivedEvent
+ extends EventObject
+{
+ private Call call = null;
+
+
+ public CallReceivedEvent(Call call)
+ {
+ super(call);
+ }
+
+ public CallParticipant getCallParticipant()
+ {
+ return (CallParticipant)getSource();
+ }
+
+ public Call getCall()
+ {
+ return (Call)getSource();
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileListener.java b/src/net/java/sip/communicator/service/protocol/event/FileListener.java
new file mode 100644
index 0000000..cc19ba3
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileListener.java
@@ -0,0 +1,20 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+/**
+ *
+ *
+ * @author Emil Ivov
+ */
+public interface FileListener
+ extends EventListener
+{
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/PresenceStatusListener.java b/src/net/java/sip/communicator/service/protocol/event/PresenceStatusListener.java
new file mode 100644
index 0000000..488fcfd
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/PresenceStatusListener.java
@@ -0,0 +1,20 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public interface PresenceStatusListener
+ extends EventListener
+{
+ public void contactPresenceStatusChanged();
+
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/ProviderChangeListener.java b/src/net/java/sip/communicator/service/protocol/event/ProviderChangeListener.java
new file mode 100644
index 0000000..f947f02
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/ProviderChangeListener.java
@@ -0,0 +1,25 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.service.protocol.event;
+
+/**
+ * An event listener that should be implemented by parties interested in changes
+ * that occur in the state of a ProtocolProvider (e.g. PresenceStatusChanges)
+ * @author Emil Ivov
+ */
+public interface ProviderChangeListener
+{
+ /**
+ * The method is called by a ProtocolProvider implementation whenver
+ * a change in the presence status of the corresponding provider had
+ * occurred.
+ * @param evt ProviderStatusChangeEvent the event describing the status
+ * change.
+ */
+ public void providerStatusChanged(ProviderStatusChangeEvent evt);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/ProviderStatusChangeEvent.java b/src/net/java/sip/communicator/service/protocol/event/ProviderStatusChangeEvent.java
new file mode 100644
index 0000000..2618285
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/ProviderStatusChangeEvent.java
@@ -0,0 +1,67 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.beans.PropertyChangeEvent;
+import net.java.sip.communicator.service.protocol.PresenceStatus;
+import net.java.sip.communicator.service.protocol.ProtocolProviderService;
+
+/**
+ * Instances of this class represent a change in the status of the provider
+ * that triggerred them.
+ * @author Emil Ivov
+ */
+public class ProviderStatusChangeEvent extends PropertyChangeEvent
+{
+
+ /**
+ * Creates an event instance indicating a change of the property
+ * specified by <code>eventType</code> from <code>oldValue</code> to
+ * <code>newValue</code>.
+ * @param source the provider that generated the event
+ * @param eventType the type of the newly created event.
+ * @param oldValue the status the source provider was int before enetering
+ * the new state.
+ * @param newValue the status the source provider is currently in.
+ */
+ public ProviderStatusChangeEvent(ProtocolProviderService source, String eventType,
+ PresenceStatus oldValue, PresenceStatus newValue)
+ {
+ super(source, eventType, oldValue, newValue);
+ }
+
+ /**
+ * Returns the provider that has genereted this event
+ * @return the provider that generated the event.
+ */
+ public ProtocolProviderService getProvider()
+ {
+ return (ProtocolProviderService)getSource();
+ }
+
+ /**
+ * Returns the status of the provider before this event took place.
+ * @return a PresenceStatus instance indicating the event the source
+ * provider was in before it entered its new state.
+ */
+ public PresenceStatus getOldStatusValue()
+ {
+ return (PresenceStatus)super.getOldValue();
+ }
+
+ /**
+ * Returns the status of the provider after this event took place.
+ * (i.e. at the time the event is being dispatched).
+ * @return a PresenceStatus instance indicating the event the source
+ * provider is in after the status change occurred.
+ */
+ public PresenceStatus getNewStatusValue()
+ {
+ return (PresenceStatus)super.getNewValue();
+ }
+
+}
diff --git a/src/net/java/sip/communicator/service/resources/FileAccessService.java b/src/net/java/sip/communicator/service/resources/FileAccessService.java
new file mode 100644
index 0000000..580d307
--- /dev/null
+++ b/src/net/java/sip/communicator/service/resources/FileAccessService.java
@@ -0,0 +1,124 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.resources;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A service used to provide the basic functionality required to access the
+ * undelaying file system.
+ *
+ * Note: Never store unencrypted sensitive information, such as passwords,
+ * personal data, credit card numbers, etc..
+ *
+ * @author Alexander Pelov
+ */
+public interface FileAccessService {
+
+ /**
+ * The key of the system property containing the user home dir
+ */
+ public static final String SYSPROPERTYKEY_USER_HOME = "user.home";
+
+ /**
+ * The key of the configuration property containing the user home dir - if
+ * it is not defined the system property is used
+ */
+ public static final String CONFPROPERTYKEY_USER_HOME = "sipcommunicator.user.home";
+
+ /**
+ * The subdirectory of USER_HOME in which all user files will be stored
+ */
+ public static final String CONFPROPERTYKEY_SIP_DIRECTORY = "sipcommunicator.user.home.sipdir";
+
+ /**
+ * The default subdirectory
+ */
+ public static final String DEFAULT_SIP_DIRECTORY = ".sipcommunicator";
+
+ /**
+ * This method returns a created temporary file. After you close this file
+ * it is not guaranteed that you will be able to open it again nor that it
+ * will contain any information.
+ *
+ * Note: DO NOT store unencrypted sensitive information in this file
+ *
+ * @return The created temporary file
+ * @throws IOException
+ * If the file cannot be created
+ */
+ File getTemporaryFile() throws IOException;
+
+ /**
+ * This method returns a created temporary directory. Any file you create
+ * in it will be a temporary file.
+ *
+ * Note: If there is no opened file in this directory it may be deleted
+ * at any time.
+ * Note: DO NOT store unencrypted sensitive information in this directory
+ *
+ * @return The created directory
+ * @throws IOException
+ * If the directory cannot be created
+ */
+ File getTemporaryDirectory() throws IOException;
+
+ /**
+ * This method returns a file specific to the current user. It may not
+ * exist, but it is guaranteed that you will have the sufficient rights to
+ * create it.
+ *
+ * This file should not be considered secure because the implementor may
+ * return a file accesible to everyone. Generaly it will reside in
+ * current user's homedir, but it may as well reside in a shared directory.
+ *
+ * Note: DO NOT store unencrypted sensitive information in this file
+ *
+ * @param fileName
+ * The name of the private file you wish to access
+ * @return The file
+ * @throws Exception
+ * Thrown if there is no suitable location for the persistent
+ * file
+ */
+ File getPrivatePersistentFile(String fileName) throws Exception;
+
+ /**
+ * This method creates a directory specific to the current user.
+ *
+ * This directory should not be considered secure because the implementor may
+ * return a directory accesible to everyone. Generaly it will reside in
+ * current user's homedir, but it may as well reside in a shared directory.
+ *
+ * It is guaranteed that you will be able to create files in it.
+ *
+ * Note: DO NOT store unencrypted sensitive information in this file
+ *
+ * @param dirName
+ * The name of the private directory you wish to access.
+ * @return The created directory.
+ * @throws Exception
+ * Thrown if there is no suitable location for the persistent
+ * directory.
+ */
+ File getPrivatePersistentDirectory(String dirName) throws Exception;
+
+ /**
+ * This method creates a directory specific to the current user.
+ *
+ * {@link #getPrivatePersistentDirectory(String)}
+ *
+ * @param dirNames
+ * The name of the private directory you wish to access.
+ * @return The created directory.
+ * @throws Exception
+ * Thrown if there is no suitable location for the persistent
+ * directory.
+ */
+ File getPrivatePersistentDirectory(String[] dirNames) throws Exception;
+}
diff --git a/src/net/java/sip/communicator/sick/netaddr/.cvsignore b/src/net/java/sip/communicator/sick/netaddr/.cvsignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/net/java/sip/communicator/sick/netaddr/.cvsignore
diff --git a/src/net/java/sip/communicator/slick/.cvsignore b/src/net/java/sip/communicator/slick/.cvsignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/net/java/sip/communicator/slick/.cvsignore
diff --git a/src/net/java/sip/communicator/slick/netaddr/.cvsignore b/src/net/java/sip/communicator/slick/netaddr/.cvsignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/net/java/sip/communicator/slick/netaddr/.cvsignore
diff --git a/src/net/java/sip/communicator/slick/netaddr/TestAddressPool.java b/src/net/java/sip/communicator/slick/netaddr/TestAddressPool.java
new file mode 100644
index 0000000..303f5c0
--- /dev/null
+++ b/src/net/java/sip/communicator/slick/netaddr/TestAddressPool.java
@@ -0,0 +1,21 @@
+package net.java.sip.communicator.slick.netaddr;
+
+import junit.framework.*;
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public class TestAddressPool
+ extends TestCase
+{
+ public TestAddressPool()
+ {
+ super();
+ }
+
+ public TestAddressPool(String name)
+ {
+ super(name);
+ }
+}
diff --git a/src/net/java/sip/communicator/util/Activator.java b/src/net/java/sip/communicator/util/Activator.java
new file mode 100644
index 0000000..cef2221
--- /dev/null
+++ b/src/net/java/sip/communicator/util/Activator.java
@@ -0,0 +1,35 @@
+package net.java.sip.communicator.util;
+
+import org.osgi.framework.*;
+
+/**
+ *
+ * @author Emil Ivov
+ */
+public class Activator
+ implements BundleActivator
+{
+ private Logger logger = Logger.getLogger(getClass().getName());
+ /**
+ * start
+ *
+ * @param bundleContext BundleContext
+ * @throws Exception
+ * @todo Implement this org.osgi.framework.BundleActivator method
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ logger.debug("Successfully activated!");
+ }
+
+ /**
+ * stop
+ *
+ * @param bundlecontext BundleContext
+ * @throws Exception
+ * @todo Implement this org.osgi.framework.BundleActivator method
+ */
+ public void stop(BundleContext bundlecontext) throws Exception
+ {
+ }
+}
diff --git a/src/net/java/sip/communicator/util/Assert.java b/src/net/java/sip/communicator/util/Assert.java
new file mode 100644
index 0000000..593e4e5
--- /dev/null
+++ b/src/net/java/sip/communicator/util/Assert.java
@@ -0,0 +1,80 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */package net.java.sip.communicator.util;
+
+/**
+ * @author Alexander Pelov
+ */
+public class Assert {
+ /**
+ * The logger for this class.
+ */
+ private static final Logger log = Logger.getLogger(Assert.class.getName());
+
+ /**
+ * Enables or disables assertion checks.
+ */
+ public static boolean EnableAssertions = true;
+
+ /**
+ * Throws an exception if the passed condition is false and
+ * <code>EnableAssertions == true</code>.
+ *
+ * @param condition The condition to be met.
+ * @param message The message to be displayed as explanation on assertion fail.
+ * @throws IllegalArgumentException Thrown if condition is false and
+ * assertions are enabled.
+ */
+ public static final void assertTrue(boolean condition, String message) throws AssertionError {
+ if (EnableAssertions && !condition) {
+ StackTraceElement caller = new Throwable().getStackTrace()[1];
+
+ String fullText = "Assertion failed at " + caller.getMethodName() + ", line " +
+ caller.getLineNumber() +
+ "\n\tMessage: " + message;
+
+ log.error(fullText);
+
+ throw new AssertionError(fullText);
+ }
+ }
+
+ /**
+ * Throws an exception if <code>EnableAssertions == true</code>.
+ *
+ * @param message The message to be displayed as explanation on assertion fail.
+ * @throws IllegalArgumentException Thrown if assertions are enabled.
+ */
+ public static final void fail(String message) throws AssertionError {
+ Assert.assertTrue(false, message);
+ }
+
+ /**
+ * Throws an exception if the passed object is null and
+ * <code>EnableAssertions == true</code>.
+ *
+ * @param obj The object to be checked.
+ * @param message The message to be displayed as explanation on assertion fail.
+ * @throws IllegalArgumentException Thrown if obj is null
+ * and assertions are enabled.
+ */
+ public static final void assertNonNull(Object obj, String message) throws AssertionError {
+ Assert.assertTrue(obj != null, message);
+ }
+
+ /**
+ * Throws an exception if the passed object is not null and
+ * <code>EnableAssertions == true</code>.
+ *
+ * @param obj The object to be checked.
+ * @param message The message to be displayed as explanation on assertion fail.
+ * @throws IllegalArgumentException Thrown if obj is not null and
+ * assertions are enabled.
+ */
+ public static final void assertNull(Object obj, String message) throws AssertionError {
+ Assert.assertTrue(obj == null, message);
+ }
+}
diff --git a/src/net/java/sip/communicator/util/BidirectionalIterator.java b/src/net/java/sip/communicator/util/BidirectionalIterator.java
new file mode 100644
index 0000000..19675e5
--- /dev/null
+++ b/src/net/java/sip/communicator/util/BidirectionalIterator.java
@@ -0,0 +1,38 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * The standard Java Iterator is uni-directional, allowing the user to explore
+ * the contents of a collection in one way only. This interface defines a
+ * bi-directional iterator, permiting the user to go forwards and backwards in
+ * a collection.
+ *
+ * @author Alexander Pelov
+ */
+public interface BidirectionalIterator extends Iterator {
+ /**
+ * Returns true if the iteration has elements preceeding the current one.
+ * (In other words, returns true if <code>prev</code> would return an element rather
+ * than throwing an exception.)
+ *
+ * @return true if the iterator has preceeding elements.
+ */
+ boolean hasPrev();
+
+ /**
+ * Returns the previous element in the iteration.
+ *
+ * @return the previous element in the iteration.
+ *
+ * @throws NoSuchElementException iteration has no more elements.
+ */
+ Object prev() throws NoSuchElementException;
+}
diff --git a/src/net/java/sip/communicator/util/EnumerationBase.java b/src/net/java/sip/communicator/util/EnumerationBase.java
new file mode 100644
index 0000000..22d14ff
--- /dev/null
+++ b/src/net/java/sip/communicator/util/EnumerationBase.java
@@ -0,0 +1,124 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * The base class for all enumerated types. One uses this class by extending it
+ * and defining "static final" constants, like this:
+ *
+ * <code>
+ * public class Color extends EnumerationBase {
+ *
+ * public static final Color Red = new Color("Red");
+ * public static final Color Blue = new Color("Blue");
+ * public static final Color Green = new Color("Green");
+ *
+ * protected Color(String description) {
+ * super(description);
+ * }
+ *
+ * }
+ * </code>
+ *
+ *
+ * Note: always compare the enum constants with <code>equals</code>, because
+ * serialization and multiple class loaders can cause alot of hard to trace bugs
+ *
+ * For more information on the issue see
+ *
+ * @link http://www.javaworld.com/javaworld/javatips/jw-javatip122.html and
+ * @link http://www.javaworld.com/javaworld/javatips/jw-javatip133.html
+ *
+ * @author Alexander Pelov
+ */
+public abstract class EnumerationBase {
+
+ private String description;
+
+ /**
+ * Constructs an enumeration element
+ *
+ * @param description
+ * The description of this element. Should be unique
+ */
+ protected EnumerationBase(String description) {
+ Assert.assertNonNull(description, "Enumeration description should be non-null");
+
+ this.description = description;
+ }
+
+ public final String toString() {
+ return this.description;
+ }
+
+ /**
+ * This method searches through all static fields defined in a class
+ * which are of type derived from EnumerationBase and returns the one whose
+ * description matches the desired one. It is the "inverse" of toString.
+ *
+ * Typical usage:
+ * WeekdaysEnumeration monday = (WeekdaysEnumeration)
+ * EnumerationBase.fromString(WeekdaysEnumeration.class, "Monday");
+ *
+ * Note: You should test to see the exact type of the object. A "blind" cast
+ * may cause an exception if the object is of a type superior to the one
+ * you are testing.
+ *
+ * @param clazz The class whose static fields will be tested. The
+ * static fields defined in it and its parents will be tested
+ * for description match.
+ * @param description The desired description to be matched.
+ * @return The field matching the description. Null if no field matches the
+ * description.
+ */
+ public static EnumerationBase fromString(Class clazz,
+ String description)
+ {
+ if(clazz == null || description == null) {
+ return null;
+ }
+
+ EnumerationBase retVal = null;
+
+ Field[] fields = clazz.getFields();
+
+ for(int i = 0; i < fields.length; i++) {
+ if((Modifier.STATIC & fields[i].getModifiers()) != 0 &&
+ EnumerationBase.class.isAssignableFrom(fields[i].getType()))
+ {
+ try {
+ EnumerationBase e = (EnumerationBase)fields[i].get(null);
+ if(e.descriptionEquals(description)) {
+ retVal = e;
+ break;
+ }
+ } catch (Exception e) {}
+ }
+ }
+
+ return retVal;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof EnumerationBase) {
+ return this.description.equals(((EnumerationBase) obj).description);
+ }
+ return false;
+ }
+
+ public boolean descriptionEquals(String str) {
+ return this.description.equals(str);
+ }
+
+ public boolean descriptionEqualsIgnoreCase(String str) {
+ return this.description.equalsIgnoreCase(str);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/util/Logger.java b/src/net/java/sip/communicator/util/Logger.java
new file mode 100644
index 0000000..b95829c
--- /dev/null
+++ b/src/net/java/sip/communicator/util/Logger.java
@@ -0,0 +1,353 @@
+package net.java.sip.communicator.util;
+
+import java.util.logging.*;
+
+/**
+ * Standard logging methods.
+ *
+ * @author Emil Ivov
+ */
+public class Logger
+{
+ private java.util.logging.Logger loggerDelegate = null;
+
+ /**
+ * Base constructor
+ *
+ * @param logger the implementation specific logger delegate that this
+ * Logger instance should be created around.
+ */
+ private Logger(java.util.logging.Logger logger)
+ {
+ this.loggerDelegate = logger;
+ }
+
+
+ /**
+ * Find or create a logger for the specified class. If a logger has
+ * already been created for that class it is returned. Otherwise
+ * a new logger is created.
+ * <p>
+ * If a new logger is created its log level will be configured
+ * based on the logging configuration and it will be configured
+ * to also send logging output to its parent's handlers.
+ * <p>
+ * @param clazz The creating class.
+ * <p>
+ * @return a suitable Logger
+ * @throws NullPointerException if the name is null.
+ */
+ public static Logger getLogger(Class clazz)
+ throws NullPointerException
+ {
+ return getLogger(clazz.getName());
+ }
+
+ /**
+ * Find or create a logger for a named subsystem. If a logger has
+ * already been created with the given name it is returned. Otherwise
+ * a new logger is created.
+ * <p>
+ * If a new logger is created its log level will be configured
+ * based on the logging configuration and it will be configured
+ * to also send logging output to its parent's handlers.
+ * <p>
+ * @param name A name for the logger. This should be a dot-separated name
+ * and should normally be based on the class name of the creator, such as
+ * "net.java.sip.communicator.MyFunnyClass"
+ * <p>
+ * @return a suitable Logger
+ * @throws NullPointerException if the name is null.
+ */
+ public static Logger getLogger(String name)
+ throws NullPointerException
+ {
+ return new Logger(java.util.logging.Logger.getLogger(name));
+
+ }
+
+
+ /**
+ * Logs an entry in the calling method.
+ */
+ public void logEntry()
+ {
+ if (loggerDelegate.isLoggable(Level.FINEST)) {
+ StackTraceElement caller = new Throwable().getStackTrace()[1];
+ loggerDelegate.log(Level.FINEST, "[entry] " + caller.getMethodName());
+ }
+ }
+
+ /**
+ * Logs exiting the calling method
+ */
+ public void logExit()
+ {
+ if (loggerDelegate.isLoggable(Level.FINEST)) {
+ StackTraceElement caller = new Throwable().getStackTrace()[1];
+ loggerDelegate.log(Level.FINEST, "[exit] " + caller.getMethodName());
+ }
+ }
+
+ /**
+ * Check if a message with a TRACE level would actually be logged by this
+ * logger.
+ * <p>
+ * @return true if the TRACE level is currently being logged
+ */
+ public boolean isTraceEnabled()
+ {
+ return loggerDelegate.isLoggable(Level.FINER);
+ }
+
+ /**
+ * Log a TRACE message.
+ * <p>
+ * If the logger is currently enabled for the TRACE message
+ * level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * <p>
+ * @param msg The message to log
+ */
+ public void trace(Object msg)
+ {
+ loggerDelegate.finer(msg!=null?msg.toString():"null");
+ }
+
+ /**
+ * Log a message, with associated Throwable information.
+ * <p>
+ * @param msg The message to log
+ * @param t Throwable associated with log message.
+ */
+ public void trace(Object msg, Throwable t)
+ {
+ loggerDelegate.log(Level.FINER, msg!=null?msg.toString():"null", t);
+ }
+
+ /**
+ * Check if a message with a DEBUG level would actually be logged by this
+ * logger.
+ * <p>
+ * @return true if the DEBUG level is currently being logged
+ */
+ public boolean isDebugEnabled()
+ {
+ return loggerDelegate.isLoggable(Level.FINE);
+ }
+
+ /**
+ * Log a DEBUG message.
+ * <p>
+ * If the logger is currently enabled for the DEBUG message
+ * level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * <p>
+ * @param msg The message to log
+ */
+ public void debug(Object msg)
+ {
+ loggerDelegate.fine(msg!=null?msg.toString():"null");
+ }
+
+ /**
+ * Log a message, with associated Throwable information.
+ * <p>
+ * @param msg The message to log
+ * @param t Throwable associated with log message.
+ */
+ public void debug(Object msg, Throwable t)
+ {
+ loggerDelegate.log(Level.FINE, msg!=null?msg.toString():"null", t);
+ }
+
+ /**
+ * Check if a message with an INFO level would actually be logged by this
+ * logger.
+ *
+ * @return true if the INFO level is currently being logged
+ */
+ public boolean isInfoEnabled()
+ {
+ return loggerDelegate.isLoggable(Level.INFO);
+ }
+
+ /**
+ * Log a INFO message.
+ * <p>
+ * If the logger is currently enabled for the INFO message
+ * level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * <p>
+ * @param msg The message to log
+ */
+ public void info(Object msg)
+ {
+ loggerDelegate.info(msg!=null?msg.toString():"null");
+ }
+
+ /**
+ * Log a message, with associated Throwable information.
+ * <p>
+ * @param msg The message to log
+ * @param t Throwable associated with log message.
+ */
+ public void info(Object msg, Throwable t)
+ {
+ loggerDelegate.log(Level.INFO, msg!=null?msg.toString():"null", t);
+ }
+
+ /**
+ * Log a WARN message.
+ * <p>
+ * If the logger is currently enabled for the WARN message
+ * level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * <p>
+ * @param msg The message to log
+ */
+ public void warn(Object msg)
+ {
+ loggerDelegate.warning(msg!=null?msg.toString():"null");
+ }
+
+ /**
+ * Log a message, with associated Throwable information.
+ * <p>
+ * @param msg The message to log
+ * @param t Throwable associated with log message.
+ */
+ public void warn(Object msg, Throwable t)
+ {
+ loggerDelegate.log(Level.WARNING, msg!=null?msg.toString():"null", t);
+ }
+
+ /**
+ * Log a ERROR message.
+ * <p>
+ * If the logger is currently enabled for the ERROR message
+ * level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * <p>
+ * @param msg The message to log
+ */
+ public void error(Object msg)
+ {
+ loggerDelegate.severe(msg!=null?msg.toString():"null");
+ }
+
+ /**
+ * Log a message, with associated Throwable information.
+ * <p>
+ * @param msg The message to log
+ * @param t Throwable associated with log message.
+ */
+ public void error(Object msg, Throwable t)
+ {
+ loggerDelegate.log(Level.SEVERE, msg!=null?msg.toString():"null", t);
+ }
+
+ /**
+ * Log a FATAL message.
+ * <p>
+ * If the logger is currently enabled for the FATAL message
+ * level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * <p>
+ * @param msg The message to log
+ */
+ public void fatal(Object msg)
+ {
+ loggerDelegate.severe(msg!=null?msg.toString():"null");
+ }
+
+ /**
+ * Log a message, with associated Throwable information.
+ * <p>
+ * @param msg The message to log
+ * @param t Throwable associated with log message.
+ */
+ public void fatal(Object msg, Throwable t)
+ {
+ loggerDelegate.log(Level.SEVERE, msg!=null?msg.toString():"null", t);
+ }
+
+ /**
+ * Set logging level for all handlers to FATAL
+ */
+ public void setLevelFatal()
+ {
+ setLevel(Level.SEVERE);
+ }
+
+ /**
+ * Set logging level for all handlers to ERROR
+ */
+ public void setLevelError()
+ {
+ setLevel(Level.SEVERE);
+ }
+
+ /**
+ * Set logging level for all handlers to WARNING
+ */
+ public void setLevelWarn()
+ {
+ setLevel(Level.WARNING);
+ }
+
+ /**
+ * Set logging level for all handlers to INFO
+ */
+ public void setLevelInfo()
+ {
+ setLevel(Level.INFO);
+ }
+
+ /**
+ * Set logging level for all handlers to DEBUG
+ */
+ public void setLevelDebug()
+ {
+ setLevel(Level.FINE);
+ }
+
+ /**
+ * Set logging level for all handlers to TRACE
+ */
+ public void setLevelTrace()
+ {
+ setLevel(Level.FINER);
+ }
+
+ /**
+ * Set logging level for all handlers to ALL (allow all log messages)
+ */
+ public void setLevelAll()
+ {
+ setLevel(Level.ALL);
+ }
+
+ /**
+ * Set logging level for all handlers to OFF (allow no log messages)
+ */
+ public void setLevelOff()
+ {
+ setLevel(Level.OFF);
+ }
+
+ /**
+ * Set logging level for all handlers to <code>level</code>
+ *
+ * @param level the level to set for all logger handlers
+ */
+ private void setLevel(java.util.logging.Level level)
+ {
+ Handler[] handlers = loggerDelegate.getHandlers();
+ for (int i = 0; i < handlers.length; i++)
+ {
+ handlers[i].setLevel(level);
+ }
+ loggerDelegate.setLevel(level);
+ }
+}
diff --git a/src/net/java/sip/communicator/util/QuoteTokenizer.java b/src/net/java/sip/communicator/util/QuoteTokenizer.java
new file mode 100644
index 0000000..83a52b3
--- /dev/null
+++ b/src/net/java/sip/communicator/util/QuoteTokenizer.java
@@ -0,0 +1,288 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * A tokenizer that takes in account the existence of " and ' and
+ * does skips all delimeters enclosed in those characters.
+ *
+ * Thus the following string:
+ *
+ * <code>This is a "stupid 'hot' dog", boy!</code>
+ *
+ * Parsed created with the default constructor will produce the
+ * following tokens:
+ *
+ * This is a
+ * "stupid 'hot' dog",
+ * boy!
+ *
+ * And the string:
+ * <code>This is a 'smart "hot" dog', boy!</code>
+ *
+ * This is a
+ * 'stupid "hot" dog',
+ * boy!
+ *
+ * @author Alexander Pelov
+ *
+ * TODO: TEST
+ */
+public class QuoteTokenizer implements Enumeration {
+
+ /**
+ * Delimeters defined for internal purposes.
+ */
+ private static final String DELIMS = "'\"";
+
+ /**
+ * The text to be tokenized.
+ */
+ private String text;
+
+ /**
+ * Delimeters requested by the user.
+ */
+ private String delims;
+
+ /**
+ * The number of tokens in the text.
+ */
+ private int tokens = -1;
+
+ /**
+ * Pointer to the current tokenizer position.
+ */
+ private int currentTokenEnd = -1;
+
+ /**
+ * Return the delimeters?
+ */
+ private boolean returnDelim;
+
+ /**
+ * Constructs a tokenizer using spaces and tabs as delimeters,
+ * not returning the delimeters as tokens.
+ *
+ * @param text The text to be tokenized
+ */
+ public QuoteTokenizer(String text) {
+ this(text, " \t");
+ }
+
+ /**
+ * Constructs a tokenizer using the characters specified in delims
+ * as delimeters, not returning the delimeters as tokens.
+ *
+ * @param text The text to be tokenized
+ * @param delims The delimeters in a string
+ */
+ public QuoteTokenizer(String text, String delims) {
+ this(text, delims, false);
+ }
+
+ /**
+ * Constructs a tokenizer using the specified delimeters, specifying
+ * if the delimeters should be returned as tokens.
+ *
+ * @param text The text to be tokenized
+ * @param delims The delimeters in a string
+ * @param returnDelim Flag specifying if the delimeters should be returned
+ */
+ public QuoteTokenizer(String text, String delims, boolean returnDelim) {
+ this.text = text;
+ this.delims = delims;
+ this.returnDelim = returnDelim;
+ }
+
+ /**
+ * Calculates the number of times that this tokenizer's
+ * <code>nextToken</code> method can be called before it
+ * generates an exception. The current position is not advanced.
+ *
+ * @return Returns the number of tokens remaining in the
+ * string using the current delimiter set
+ */
+ public int countTokens() {
+ // See if the tokens were already count
+ if(this.tokens == -1) {
+ this.tokens = performTokenCount();
+ }
+
+ return this.tokens;
+ }
+
+ /**
+ * Returns the same value as the <code>hasMoreTokens</code> method.
+ * It exists so that this class can implement the Enumeration interface.
+ */
+ public boolean hasMoreElements() {
+ return this.hasMoreTokens();
+ }
+
+ /**
+ * Tests if there are more tokens available from this
+ * tokenizer's string. If this method returns true, then a
+ * subsequent call to nextToken with no argument will
+ * successfully return a token.
+ *
+ * @return Returns true if and only if there is at
+ * least one token in the string after the current position;
+ * false otherwise.
+ */
+ public boolean hasMoreTokens() {
+ return this.currentTokenEnd < this.text.length();
+ }
+
+ /**
+ * Returns the same value as the nextToken method, except that
+ * its declared return value is Object rather than String.
+ * It exists so that this class can implement the Enumeration interface.
+ *
+ * @return Returns the next token in the string.
+ *
+ * @throws Throws NoSuchElementException - if there are no more
+ * tokens in this tokenizer's string.
+ */
+ public Object nextElement() {
+ return this.nextToken();
+ }
+
+ /**
+ * Returns the next token from this string tokenizer.
+ *
+ * @return Returns the next token from this string tokenizer.
+ * @throws Throws NoSuchElementException - if there are no more
+ * tokens in this tokenizer's string.
+ */
+ public String nextToken() throws NoSuchElementException {
+ if(!this.hasMoreTokens()) {
+ throw new NoSuchElementException();
+ }
+
+ int tokStart = this.getTokenStart(this.currentTokenEnd);
+ int tokEnd = this.getTokenEnd(tokStart);
+
+ this.currentTokenEnd = tokEnd;
+ return this.text.substring(tokStart, tokEnd);
+ }
+
+ /**
+ * Returns the next token in this string tokenizer's string.
+ * First, the set of characters considered to be delimiters
+ * by this StringTokenizer object is changed to be the characters
+ * in the string delim. Then the next token in the string after
+ * the current position is returned. The current position is
+ * advanced beyond the recognized token. The new delimiter set
+ * remains the default after this call.
+ *
+ * @param delims - the new delimeters.
+ * @return Returns the next token, after switching to the
+ * new delimiter set.
+ *
+ * @throws Throws NoSuchElementException - if there are no more
+ * tokens in this tokenizer's string.
+ */
+ public String nextToken(String delims) {
+ this.delims = delims;
+ this.tokens = -1;
+
+ return this.nextToken();
+ }
+
+ /**
+ * Restarts the tokenizer.
+ */
+ public void reset() {
+ this.currentTokenEnd = -1;
+ }
+
+ /**
+ * Restarts the tokenizer and sets new parameters.
+ */
+ public void reset(String delims, boolean returnDelim) {
+ this.reset();
+ this.delims = delims;
+ this.returnDelim = returnDelim;
+ this.tokens = -1;
+ }
+
+
+ private int performTokenCount() {
+ // No; Count them
+ int count = 1;
+
+ int tokStart = this.getTokenStart(0);
+ int tokEnd = this.getTokenEnd(tokStart);
+
+ int textLen = this.text.length();
+ while(tokEnd < textLen) {
+ tokStart = this.getTokenStart(tokEnd);
+ tokEnd = this.getTokenEnd(tokStart);
+
+ count++;
+ }
+
+ return count;
+ }
+
+ private int getTokenStart(int prevTokenEnd) {
+ int tokenStart = prevTokenEnd;
+
+ if(!this.returnDelim) {
+ int textLen = this.text.length();
+ while(tokenStart < textLen
+ &&
+ this.delims.indexOf(this.text.charAt(tokenStart)) >= 0
+ ) {
+ tokenStart++;
+ }
+ }
+
+ return tokenStart;
+ }
+
+ private int getTokenEnd(int tokenStart) {
+ return findNextDelim(tokenStart)+1;
+ }
+
+ private int findNextDelim(int start) {
+ // The end of the token
+ int nextDelim;
+
+ // Mark if a " or ' was met
+ char stringChar = 0;
+
+ int textLen = this.text.length();
+ for(nextDelim = start; nextDelim < textLen; nextDelim++) {
+ char c = this.text.charAt(nextDelim);
+
+ // Have we met a " or ' ?
+ if(stringChar == 0) {
+ // No;
+ if(this.delims.indexOf(c) >= 0) {
+ // Found Delim!! Quit!
+ break;
+ } else if(DELIMS.indexOf(c) >= 0) {
+ stringChar = c;
+ }
+ } else {
+ // Yes;
+ if(c == stringChar) {
+ stringChar = 0;
+ }
+ }
+ }
+
+ return nextDelim;
+ }
+
+
+}
diff --git a/src/net/java/sip/communicator/util/ScLogFormatter.java b/src/net/java/sip/communicator/util/ScLogFormatter.java
new file mode 100644
index 0000000..a697fdf
--- /dev/null
+++ b/src/net/java/sip/communicator/util/ScLogFormatter.java
@@ -0,0 +1,116 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util;
+
+import java.io.*;
+import java.util.logging.*;
+
+/**
+ * Print a brief summary of the LogRecord in a human readable. The summary will
+ * typically be on a single line (unless it's too long :) ... what I meant to
+ * say is that we don't add any line breaks).
+ *
+ * @author Emil Ivov
+ */
+
+public class ScLogFormatter
+ extends Formatter
+{
+ static long startTime = System.currentTimeMillis();
+
+ private static String lineSeparator = System.getProperty("line.separator");
+
+ /**
+ * Format the given LogRecord.
+ * @param record the log record to be formatted.
+ * @return a formatted log record
+ */
+ public synchronized String format(LogRecord record)
+ {
+ StringBuffer sb = new StringBuffer();
+
+ //time since the program started
+ sb.append(System.currentTimeMillis() - startTime);
+ sb.append(" ");
+
+ //log level
+ sb.append(record.getLevel().getLocalizedName());
+ sb.append(": ");
+
+ //caller method
+ inferCaller(record);
+ String loggerName = record.getLoggerName();
+ if(loggerName.startsWith("net.java.sip.communicator."))
+ sb.append(loggerName.substring("net.java.sip.communicator.".length()));
+ else
+ sb.append(record.getLoggerName());
+
+ if (record.getSourceMethodName() != null)
+ {
+ sb.append(".");
+ sb.append(record.getSourceMethodName());
+ sb.append("()");
+ }
+ sb.append(" ");
+ sb.append(record.getMessage());
+ sb.append(lineSeparator);
+ if (record.getThrown() != null)
+ {
+ try
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ record.getThrown().printStackTrace(pw);
+ pw.close();
+ sb.append(sw.toString());
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Try to extract the name of the class and method that called the current
+ * log statement.
+ *
+ * @param record the logrecord where class and method name should be stored.
+ */
+ private void inferCaller(LogRecord record)
+ {
+ // Get the stack trace.
+ StackTraceElement stack[] = (new Throwable()).getStackTrace();
+
+ // First, search back to a method in the SIP Communicator Logger class.
+ int ix = 0;
+ while (ix < stack.length)
+ {
+ StackTraceElement frame = stack[ix];
+ String cname = frame.getClassName();
+ if (cname.equals("net.java.sip.communicator.util.Logger"))
+ {
+ break;
+ }
+ ix++;
+ }
+ // Now search for the first frame before the SIP Communicator Logger class.
+ while (ix < stack.length)
+ {
+ StackTraceElement frame = stack[ix];
+ String cname = frame.getClassName();
+ if (!cname.equals("net.java.sip.communicator.util.Logger"))
+ {
+ // We've found the relevant frame.
+ record.setSourceClassName(cname);
+ record.setSourceMethodName(frame.getMethodName());
+ break;
+ }
+ ix++;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/util/util.manifest.mf b/src/net/java/sip/communicator/util/util.manifest.mf
new file mode 100644
index 0000000..30fb569
--- /dev/null
+++ b/src/net/java/sip/communicator/util/util.manifest.mf
@@ -0,0 +1,17 @@
+Bundle-Activator: net.java.sip.communicator.util.Activator
+Bundle-Name: SIP Communicator Utility Packages
+Bundle-Description: A bundle that export packages with utility classes.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.w3c.dom,
+ org.xml.sax,
+ javax.xml.parsers,
+ org.apache.xml.serializer,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
+ net.java.sip.communicator.util.xml,
+ net.java.sip.communicator.util,
+Export-Package: net.java.sip.communicator.util.xml,
+ net.java.sip.communicator.util,
+
diff --git a/src/net/java/sip/communicator/util/xml/XMLException.java b/src/net/java/sip/communicator/util/xml/XMLException.java
new file mode 100644
index 0000000..88e093c
--- /dev/null
+++ b/src/net/java/sip/communicator/util/xml/XMLException.java
@@ -0,0 +1,45 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util.xml;
+
+/**
+ * The class is used to mask any XML specific exceptions thrown during parsing
+ * various descriptors.
+ *
+ * @author Emil Ivov
+ * @version 1.0
+ */
+
+public class XMLException extends Exception
+{
+ /**
+ * Constructs a new XMLException with the specified detail message and cause.
+ *
+ * @param message a message specifying the reason that caused the
+ * exception.
+ *
+ * @param cause the cause (which is saved
+ * for later retrieval by the Throwable.getCause() method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or unknown.)
+ */
+ public XMLException(String message, Throwable cause)
+ {
+ super (message, cause);
+ }
+
+ /**
+ * Constructs a new XMLException with the specified detail message.
+ *
+ * @param message a message specifying the reason that caused the
+ * exception.
+ */
+ public XMLException(String message)
+ {
+ super(message);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/util/xml/XMLUtils.java b/src/net/java/sip/communicator/util/xml/XMLUtils.java
new file mode 100644
index 0000000..01a279a
--- /dev/null
+++ b/src/net/java/sip/communicator/util/xml/XMLUtils.java
@@ -0,0 +1,403 @@
+package net.java.sip.communicator.util.xml;
+
+
+import java.io.*;
+import org.w3c.dom.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Common XML Tasks
+ *
+ * @author Emil Ivov
+ * @author Damian Minkov
+ */
+public class XMLUtils
+{
+ private static Logger logger = Logger.getLogger(XMLUtils.class);
+ /**
+ * Extracts from node the attribute with the specified name.
+ * @param node the node whose attribute we'd like to extract.
+ * @param name the name of the attribute to extract.
+ * @return a String containing the trimmed value of the attribute or null
+ * if no such attribute exists
+ */
+ public static String getAttribute(Node node, String name)
+ {
+ try
+ {
+ logger.logEntry();
+
+ if(node == null)
+ return null;
+
+ Node attribute = node.getAttributes().getNamedItem(name);
+ return (attribute==null)? null : attribute.getNodeValue().trim();
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Extracts the String content of a TXT element.
+ *
+ * @param parentNode the node containing the data that we'd like to get.
+ * @return the string contained by the node or null if none existed.
+ */
+ public static String getText(Element parentNode)
+ {
+ try
+ {
+ logger.logEntry();
+
+ Text text = getTextNode(parentNode);
+
+ if (text == null){
+ return null;
+ }
+ else{
+ return text.getData();
+ }
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Sets data to be the TEXT content of element
+ *
+ * @param parentNode the parent element.
+ * @param data the data to set.
+ */
+ public static void setText(Element parentNode, String data)
+ {
+ try
+ {
+ logger.logEntry();
+
+ Text txt = getTextNode(parentNode);
+
+ if(txt != null)
+ txt.setData(data);
+ else
+ {
+ txt = parentNode.getOwnerDocument().createTextNode(data);
+ parentNode.appendChild(txt);
+ }
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Sets data to be the CDATA content of element
+ *
+ * @param element the parent element.
+ * @param data the data to set.
+ */
+ public static void setCData(Element element, String data)
+ {
+ try
+ {
+ logger.logEntry();
+
+ CDATASection txt = getCDataNode(element);
+ if(txt != null)
+ txt.setData(data);
+ else
+ {
+ txt = element.getOwnerDocument().createCDATASection(data);
+ element.appendChild(txt);
+ }
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Extract the CDATA content of the specified element.
+ * @param element the element whose data we need
+ * @return a String containing the CDATA value of element.
+ */
+ public static String getCData(Element element)
+ {
+ try
+ {
+ logger.logEntry();
+
+ CDATASection text = getCDataNode(element);
+ if(text != null)
+ return text.getData().trim();
+ else
+ return null;
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+
+ /**
+ * Returns element's CDATA child node (if it has one).
+ * @param element the element whose CDATA we need to get.
+ * @return a CDATASection object containing the specified element's CDATA
+ * content
+ */
+ public static CDATASection getCDataNode(Element element)
+ {
+ try
+ {
+ logger.logEntry();
+
+ return (CDATASection)getChildByType(element,
+ Node.CDATA_SECTION_NODE);
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Returns element's TEXXT child node (if it has one).
+ * @param element the element whose TEXT we need to get.
+ * @return a <code>Text</code> object containing the specified element's
+ * text content.
+ */
+ public static Text getTextNode(Element element)
+ {
+ try
+ {
+ logger.logEntry();
+
+ return (Text)getChildByType(element, Node.TEXT_NODE);
+ }
+ finally
+ {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Returns first of the <code>element</code>'s child nodes that is of type
+ * <code>nodeType</code>.
+ * @param element the element whose child we need.
+ * @param nodeType the type of the child we need.
+ * @return a child of the specified <code>nodeType</code> or null if none
+ * was found.
+ */
+ public static Node getChildByType(Element element, short nodeType)
+ {
+ try{
+ logger.logEntry();
+
+ if (element == null)
+ return null;
+
+ NodeList nodes = element.getChildNodes();
+ if (nodes == null || nodes.getLength() < 1)
+ return null;
+
+ Node node;
+ String data;
+ for (int i = 0; i < nodes.getLength(); i++)
+ {
+ node = nodes.item(i);
+ short type = node.getNodeType();
+ if (type == nodeType)
+ {
+ if (type == Node.TEXT_NODE ||
+ type == Node.CDATA_SECTION_NODE)
+ {
+ data = ( (Text) node).getData();
+ if (data == null || data.trim().length() < 1)
+ continue;
+ }
+
+ return node;
+ }
+ }
+
+ return null;
+ }finally{
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Writes the specified document to the given file adding indentatation.
+ * The default encoding is UTF-8.
+ *
+ * @param out the output File
+ * @param document the document to write
+ *
+ * @throws java.io.IOException in case a TransformerException is thrown by
+ * the underlying Transformer.
+ */
+ public static void writeXML(Document document, File out)
+ throws java.io.IOException
+ {
+ writeXML(document, new StreamResult(out), null, null);
+ }
+
+ /**
+ * Writes the specified document to the given file adding indentatation.
+ * The default encoding is UTF-8.
+ *
+ * @param writer the writer to use when writing the File
+ * @param document the document to write
+ *
+ * @throws java.io.IOException in case a TransformerException is thrown by
+ * the underlying Transformer.
+ */
+ public static void writeXML(Document document,
+ Writer writer)
+ throws java.io.IOException
+ {
+ writeXML(document, new StreamResult(writer), null, null);
+ }
+
+ /**
+ * Writes the specified document to the given file adding indentatation.
+ * The default encoding is UTF-8.
+ *
+ * @param streamResult the streamResult object where the document should be
+ * written
+ * @param document the document to write
+ * @param doctypeSystem the doctype system of the xml document that we should
+ * record in the file or null if none is specified.
+ * @param doctypePublic the public identifier to be used in the document
+ * type declaration.
+ *
+ * @throws java.io.IOException in case a TransformerException is thrown by
+ * the underlying Transformer.
+ */
+ public static void writeXML(Document document,
+ StreamResult streamResult,
+ String doctypeSystem,
+ String doctypePublic)
+ throws java.io.IOException
+ {
+ try {
+ logger.logEntry();
+
+ DOMSource domSource = new DOMSource(document);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer serializer = tf.newTransformer();
+ if(doctypeSystem != null)
+ serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
+ doctypeSystem);
+ if(doctypePublic != null)
+ serializer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
+ doctypePublic);
+ serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+ serializer.transform(domSource, streamResult);
+ }
+ catch (TransformerException ex) {
+ logger.error("Error saving configuration file", ex);
+ throw new java.io.IOException(
+ "Failed to write the configuration file: "
+ + ex.getMessageAndLocation());
+ }
+ catch (IllegalArgumentException ex) {
+ //this one is thrown by the setOutputProperty or in other words -
+ //shoudln't happen. so let's just log it down in case ...
+ logger.error("Error saving configuration file", ex);
+ }
+ finally {
+ logger.logExit();
+ }
+ }
+
+ /**
+ * Whenever you'd need to print a configuration node and/or its children.
+ *
+ * @param root the root node to print.
+ * @param out the print stream that should be used to outpu
+ * @param recurse boolean
+ * @param prefix String
+ */
+ public static void printChildElements(Element root,
+ PrintStream out,
+ boolean recurse,
+ String prefix)
+ {
+ out.print(prefix + "<" + root.getNodeName());
+ NamedNodeMap attrs = root.getAttributes();
+ Node node;
+ for(int i = 0; i < attrs.getLength(); i++)
+ {
+ node = attrs.item(i);
+ out.print(" " + node.getNodeName() + "=\""
+ + node.getNodeValue() + "\"");
+ }
+ out.println(">");
+
+ String data = getText(root);
+ if(data != null && data.trim().length() > 0)
+ out.println(prefix + "\t" + data);
+
+ data = getCData(root);
+ if(data != null && data.trim().length() > 0)
+ out.println(prefix + "\t<![CDATA[" + data + "]]>");
+
+ NodeList nodes = root.getChildNodes();
+ for(int i = 0; i < nodes.getLength(); i++)
+ {
+ node = nodes.item(i);
+ if(node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if(recurse)
+ printChildElements((Element)node, out, recurse, prefix
+ + "\t");
+ else
+ out.println(prefix + node.getNodeName());
+ }
+ }
+
+ out.println(prefix + "</" + root.getNodeName() + ">");
+ }
+
+ /**
+ * Returns the child element with the specified tagName for the specified
+ * parent element.
+ * @param parent The parent whose child we're looking for.
+ * @param tagName the name of the child to find
+ * @return The child with the specified name or null if no such child was
+ * found.
+ * @throws NullPointerException if parent or tagName are null
+ */
+ public static Element findChild(Element parent, String tagName)
+ {
+ if(parent == null || tagName == null)
+ throw new NullPointerException("Parent or tagname were null! "
+ + "parent = " + parent + "; tagName = " + tagName);
+
+ NodeList nodes = parent.getChildNodes();
+ Node node;
+ int len = nodes.getLength();
+ for(int i = 0; i < len; i++)
+ {
+ node = nodes.item(i);
+ if(node.getNodeType() == Node.ELEMENT_NODE
+ && ((Element)node).getNodeName().equals(tagName))
+ return (Element)node;
+ }
+
+ return null;
+ }
+
+
+}