From 0bf4b5992290fa7f1342ede47485313002d966ee Mon Sep 17 00:00:00 2001 From: plfiorini Date: Fri, 7 May 2010 09:47:10 +0000 Subject: [PATCH] Usual SVN tree (branches, tags, trunk). --- Jamfile | 12 + Jamrules | 70 + application/Account.cpp | 30 + application/Account.h | 24 + application/AccountManager.cpp | 83 + application/AccountManager.h | 28 + application/Caya.h | 10 + application/CayaConstants.h | 138 + application/CayaProtocol.h | 42 + application/CayaResources.h | 19 + application/CayaUtils.cpp | 95 + application/CayaUtils.h | 22 + application/ChatWindow.cpp | 248 ++ application/ChatWindow.h | 40 + application/ContactLinker.cpp | 160 + application/ContactLinker.h | 64 + application/EditingFilter.cpp | 45 + application/EditingFilter.h | 21 + application/ImageCache.cpp | 98 + application/ImageCache.h | 56 + application/Jamfile | 56 + application/KeyMap.h | 117 + application/LooperCayaProtocol.cpp | 37 + application/LooperCayaProtocol.h | 25 + application/Main.cpp | 18 + application/MainWindow.cpp | 314 ++ application/MainWindow.h | 54 + application/Notifier.cpp | 49 + application/Notifier.h | 29 + application/NotifyMessage.h | 18 + application/Observer.h | 19 + application/ProtocolManager.cpp | 95 + application/ProtocolManager.h | 37 + application/ProtocolSettings.cpp | 435 +++ application/ProtocolSettings.h | 38 + application/Server.cpp | 254 ++ application/Server.h | 52 + application/TheApp.cpp | 78 + application/TheApp.h | 25 + application/WindowsManager.cpp | 35 + application/WindowsManager.h | 25 + application/caya.rdef | 95 + application/preferences/AccountListItem.cpp | 96 + application/preferences/AccountListItem.h | 36 + .../preferences/PreferencesAccounts.cpp | 300 ++ application/preferences/PreferencesAccounts.h | 28 + application/preferences/PreferencesDialog.cpp | 58 + application/preferences/PreferencesDialog.h | 17 + application/views/CayaRenderView.cpp | 93 + application/views/CayaRenderView.h | 55 + application/views/ContactPopUp.cpp | 116 + application/views/ContactPopUp.h | 38 + application/views/NicknameTextControl.cpp | 25 + application/views/NicknameTextControl.h | 17 + application/views/RosterItem.cpp | 182 ++ application/views/RosterItem.h | 57 + application/views/RosterListView.cpp | 173 ++ application/views/RosterListView.h | 31 + application/views/StatusMenuItem.cpp | 90 + application/views/StatusMenuItem.h | 33 + application/views/StatusView.cpp | 138 + application/views/StatusView.h | 34 + build/jam/BuildSettings | 113 + build/jam/CheckRules | 104 + build/jam/ConfigRules | 146 + build/jam/DistroRules | 35 + build/jam/FileRules | 31 + build/jam/HelperRules | 52 + build/jam/InstallRules | 27 + build/jam/MainBuildRules | 380 +++ build/jam/OverriddenJamRules | 218 ++ build/jam/PackageRules | 247 ++ build/jam/UserBuildConfig.sample | 63 + configure | 144 + data/icons/misc/Search | Bin 0 -> 485 bytes data/icons/status/Away | Bin 0 -> 1882 bytes data/icons/status/Busy | Bin 0 -> 1882 bytes data/icons/status/Offline | Bin 0 -> 1882 bytes data/icons/status/Online | Bin 0 -> 1882 bytes libs/Jamfile | 7 + libs/libinterface/BitmapMenuItem.cpp | 109 + libs/libinterface/BitmapMenuItem.h | 40 + libs/libinterface/BitmapUtils.cpp | 89 + libs/libinterface/BitmapUtils.h | 15 + libs/libinterface/BitmapView.cpp | 89 + libs/libinterface/BitmapView.h | 33 + libs/libinterface/Divider.cpp | 136 + libs/libinterface/Divider.h | 34 + libs/libinterface/Jamfile | 12 + libs/libinterface/NotifyingTextView.cpp | 77 + libs/libinterface/NotifyingTextView.h | 36 + libs/libinterface/PictureView.cpp | 84 + libs/libinterface/PictureView.h | 32 + libs/libjabber/Base64.cpp | 118 + libs/libjabber/Base64.h | 21 + libs/libjabber/JabberAgent.cpp | 134 + libs/libjabber/JabberAgent.h | 45 + libs/libjabber/JabberContact.cpp | 135 + libs/libjabber/JabberContact.h | 46 + libs/libjabber/JabberElement.cpp | 100 + libs/libjabber/JabberElement.h | 35 + libs/libjabber/JabberHandler.cpp | 1217 ++++++++ libs/libjabber/JabberHandler.h | 171 ++ libs/libjabber/JabberManager.h | 34 + libs/libjabber/JabberMessage.cpp | 124 + libs/libjabber/JabberMessage.h | 48 + libs/libjabber/JabberPlug.h | 25 + libs/libjabber/JabberPresence.cpp | 179 ++ libs/libjabber/JabberPresence.h | 47 + libs/libjabber/JabberRegistration.cpp | 111 + libs/libjabber/JabberRegistration.h | 46 + libs/libjabber/JabberSSLPlug.cpp | 188 ++ libs/libjabber/JabberSSLPlug.h | 53 + libs/libjabber/JabberSocketPlug.cpp | 187 ++ libs/libjabber/JabberSocketPlug.h | 41 + libs/libjabber/JabberVCard.cpp | 245 ++ libs/libjabber/JabberVCard.h | 64 + libs/libjabber/Jamfile | 34 + libs/libjabber/LICENSE | 33 + libs/libjabber/Logger.cpp | 50 + libs/libjabber/Logger.h | 10 + libs/libjabber/ObjectList.h | 866 ++++++ libs/libjabber/SHA1.cpp | 222 ++ libs/libjabber/SHA1.h | 81 + libs/libjabber/ServerHandler.h | 7 + libs/libjabber/States.h | 18 + libs/libjabber/VCardManager.cpp | 139 + libs/libjabber/VCardManager.h | 34 + libs/librunview/Emoconfig.cpp | 195 ++ libs/librunview/Emoconfig.h | 31 + libs/librunview/Emoticor.cpp | 118 + libs/librunview/Emoticor.h | 31 + libs/librunview/Jamfile | 21 + libs/librunview/NormalTextRender.h | 43 + libs/librunview/ObjectList.h | 866 ++++++ libs/librunview/RunView.cpp | 2622 +++++++++++++++++ libs/librunview/RunView.h | 190 ++ libs/librunview/SmileTextRender.h | 53 + libs/librunview/TextRender.h | 19 + libs/librunview/Theme.cpp | 265 ++ libs/librunview/Theme.h | 120 + libs/librunview/URLCrunch.cpp | 99 + libs/librunview/URLCrunch.h | 40 + libs/librunview/Utilities.cpp | 378 +++ libs/librunview/Utilities.h | 70 + libs/libsupport/Jamfile | 7 + libs/libsupport/Singleton.h | 24 + libs/private/IconUtils.h | 80 + libs/private/MenuPrivate.h | 86 + protocols/Jamfile | 4 + protocols/gtalk/GoogleTalk.cpp | 853 ++++++ protocols/gtalk/GoogleTalk.h | 114 + protocols/gtalk/Jamfile | 20 + protocols/gtalk/SettingsTemplate.rdef | 18 + protocols/gtalk/gtalk.rdef | 34 + protocols/gtalk/main.cpp | 8 + smileys/Jamfile | 87 + smileys/airplane.gif | Bin 0 -> 1196 bytes smileys/angel_smile.gif | Bin 0 -> 1233 bytes smileys/angry.gif | Bin 0 -> 1204 bytes smileys/asl.gif | Bin 0 -> 1121 bytes smileys/auto.gif | Bin 0 -> 1126 bytes smileys/baring_teeth.gif | Bin 0 -> 1218 bytes smileys/bat.gif | Bin 0 -> 1636 bytes smileys/beer_mug.gif | Bin 0 -> 1277 bytes smileys/black_sheep.gif | Bin 0 -> 1203 bytes smileys/bowl.gif | Bin 0 -> 684 bytes smileys/brb.gif | Bin 0 -> 5169 bytes smileys/broken_heart.gif | Bin 0 -> 1237 bytes smileys/cake.gif | Bin 0 -> 1232 bytes smileys/camera.gif | Bin 0 -> 1206 bytes smileys/cat.gif | Bin 0 -> 1317 bytes smileys/cigarette.gif | Bin 0 -> 2157 bytes smileys/clock.gif | Bin 0 -> 1228 bytes smileys/coffee.gif | Bin 0 -> 1144 bytes smileys/computer.gif | Bin 0 -> 1219 bytes smileys/confused.gif | Bin 0 -> 1201 bytes smileys/console.gif | Bin 0 -> 1166 bytes smileys/cry.gif | Bin 0 -> 2848 bytes smileys/devil_smile.gif | Bin 0 -> 1115 bytes smileys/dog.gif | Bin 0 -> 1179 bytes smileys/dont_know.gif | Bin 0 -> 2051 bytes smileys/dont_tell.gif | Bin 0 -> 1158 bytes smileys/envelope.gif | Bin 0 -> 1151 bytes smileys/film.gif | Bin 0 -> 1139 bytes smileys/girl.gif | Bin 0 -> 1144 bytes smileys/girl_hug.gif | Bin 0 -> 1162 bytes smileys/guy.gif | Bin 0 -> 1123 bytes smileys/guy_hug.gif | Bin 0 -> 1142 bytes smileys/hahaha.gif | Bin 0 -> 1678 bytes smileys/handcuffs.gif | Bin 0 -> 713 bytes smileys/heart.gif | Bin 0 -> 1219 bytes smileys/island_palm.gif | Bin 0 -> 1203 bytes smileys/kiss.gif | Bin 0 -> 1123 bytes smileys/lightbulb.gif | Bin 0 -> 1062 bytes smileys/lightning.gif | Bin 0 -> 5991 bytes smileys/martini.gif | Bin 0 -> 1078 bytes smileys/messenger.gif | Bin 0 -> 1248 bytes smileys/mobile_phone.gif | Bin 0 -> 632 bytes smileys/money.gif | Bin 0 -> 1243 bytes smileys/moon.gif | Bin 0 -> 698 bytes smileys/nerd.gif | Bin 0 -> 1223 bytes smileys/note.gif | Bin 0 -> 1098 bytes smileys/omg.gif | Bin 0 -> 1197 bytes smileys/party.gif | Bin 0 -> 1990 bytes smileys/phone.gif | Bin 0 -> 1216 bytes smileys/pizaa.gif | Bin 0 -> 1162 bytes smileys/pizza.gif | Bin 0 -> 1162 bytes smileys/plate.gif | Bin 0 -> 1068 bytes smileys/present.gif | Bin 0 -> 1252 bytes smileys/rainbow.gif | Bin 0 -> 1102 bytes smileys/red.gif | Bin 0 -> 1232 bytes smileys/regular_smile.gif | Bin 0 -> 1223 bytes smileys/regular_smiley.gif | Bin 0 -> 1164 bytes smileys/roll.gif | Bin 0 -> 3036 bytes smileys/rose.gif | Bin 0 -> 1064 bytes smileys/ruler.gif | Bin 0 -> 132 bytes smileys/sad_smile.gif | Bin 0 -> 1199 bytes smileys/sarcastic.gif | Bin 0 -> 1201 bytes smileys/secret.gif | Bin 0 -> 1223 bytes smileys/settings.xml | 556 ++++ smileys/settings_svg.xml | 87 + smileys/shades.gif | Bin 0 -> 1267 bytes smileys/sick.gif | Bin 0 -> 1251 bytes smileys/sleepy.gif | Bin 0 -> 1194 bytes smileys/smilec.gif | Bin 0 -> 1231 bytes smileys/snail.gif | Bin 0 -> 1127 bytes smileys/soccer.gif | Bin 0 -> 1206 bytes smileys/star.gif | Bin 0 -> 1087 bytes smileys/star2.gif | Bin 0 -> 339 bytes smileys/stormy.gif | Bin 0 -> 1229 bytes smileys/sun.gif | Bin 0 -> 1241 bytes smileys/svg/01.svg | 55 + smileys/svg/01.svg_ | 40 + smileys/svg/02.svg | 89 + smileys/svg/02.svg_ | 62 + smileys/svg/BeOS_logo.svg | 33 + smileys/svg/BeOS_logo.svg_ | 27 + smileys/svg/emoticon_1.svg | 36 + smileys/svg/emoticon_1.svg_ | 22 + smileys/svg/emoticon_2.svg | 37 + smileys/svg/emoticon_2.svg_ | 24 + smileys/svg/emoticon_3.svg | 42 + smileys/svg/emoticon_3.svg_ | 32 + smileys/svg/emoticon_4.svg | 36 + smileys/svg/emoticon_4.svg_ | 22 + smileys/svg/emoticon_5.svg | 45 + smileys/svg/emoticon_5.svg_ | 38 + smileys/svg/emoticon_6.svg | 43 + smileys/svg/emoticon_6.svg_ | 34 + smileys/svg/emoticon_7.svg | 62 + smileys/svg/emoticon_7.svg_ | 45 + smileys/svg/emoticon_8.svg | 36 + smileys/svg/emoticon_8.svg_ | 26 + smileys/svg/zeta-badge.svg | 32 + smileys/svg/zeta-badge.svg_ | 28 + smileys/teeth_smile.gif | Bin 0 -> 1216 bytes smileys/thinking.gif | Bin 0 -> 2238 bytes smileys/thumbs_down.gif | Bin 0 -> 393 bytes smileys/thumbs_up.gif | Bin 0 -> 597 bytes smileys/tongue_smile.gif | Bin 0 -> 1226 bytes smileys/turtle.gif | Bin 0 -> 1192 bytes smileys/umbrella.gif | Bin 0 -> 1139 bytes smileys/what_smile.gif | Bin 0 -> 1201 bytes smileys/wilted_rose.gif | Bin 0 -> 1038 bytes smileys/wink_smile.gif | Bin 0 -> 2208 bytes smileys/wu.gif | Bin 0 -> 681 bytes 267 files changed, 20173 insertions(+) create mode 100644 Jamfile create mode 100644 Jamrules create mode 100644 application/Account.cpp create mode 100644 application/Account.h create mode 100644 application/AccountManager.cpp create mode 100644 application/AccountManager.h create mode 100644 application/Caya.h create mode 100644 application/CayaConstants.h create mode 100644 application/CayaProtocol.h create mode 100644 application/CayaResources.h create mode 100644 application/CayaUtils.cpp create mode 100644 application/CayaUtils.h create mode 100644 application/ChatWindow.cpp create mode 100644 application/ChatWindow.h create mode 100644 application/ContactLinker.cpp create mode 100644 application/ContactLinker.h create mode 100644 application/EditingFilter.cpp create mode 100644 application/EditingFilter.h create mode 100644 application/ImageCache.cpp create mode 100644 application/ImageCache.h create mode 100644 application/Jamfile create mode 100644 application/KeyMap.h create mode 100644 application/LooperCayaProtocol.cpp create mode 100644 application/LooperCayaProtocol.h create mode 100644 application/Main.cpp create mode 100644 application/MainWindow.cpp create mode 100644 application/MainWindow.h create mode 100644 application/Notifier.cpp create mode 100644 application/Notifier.h create mode 100644 application/NotifyMessage.h create mode 100644 application/Observer.h create mode 100644 application/ProtocolManager.cpp create mode 100644 application/ProtocolManager.h create mode 100644 application/ProtocolSettings.cpp create mode 100644 application/ProtocolSettings.h create mode 100644 application/Server.cpp create mode 100644 application/Server.h create mode 100644 application/TheApp.cpp create mode 100644 application/TheApp.h create mode 100644 application/WindowsManager.cpp create mode 100644 application/WindowsManager.h create mode 100644 application/caya.rdef create mode 100644 application/preferences/AccountListItem.cpp create mode 100644 application/preferences/AccountListItem.h create mode 100644 application/preferences/PreferencesAccounts.cpp create mode 100644 application/preferences/PreferencesAccounts.h create mode 100644 application/preferences/PreferencesDialog.cpp create mode 100644 application/preferences/PreferencesDialog.h create mode 100644 application/views/CayaRenderView.cpp create mode 100644 application/views/CayaRenderView.h create mode 100644 application/views/ContactPopUp.cpp create mode 100644 application/views/ContactPopUp.h create mode 100644 application/views/NicknameTextControl.cpp create mode 100644 application/views/NicknameTextControl.h create mode 100644 application/views/RosterItem.cpp create mode 100644 application/views/RosterItem.h create mode 100644 application/views/RosterListView.cpp create mode 100644 application/views/RosterListView.h create mode 100644 application/views/StatusMenuItem.cpp create mode 100644 application/views/StatusMenuItem.h create mode 100644 application/views/StatusView.cpp create mode 100644 application/views/StatusView.h create mode 100644 build/jam/BuildSettings create mode 100644 build/jam/CheckRules create mode 100644 build/jam/ConfigRules create mode 100644 build/jam/DistroRules create mode 100644 build/jam/FileRules create mode 100644 build/jam/HelperRules create mode 100644 build/jam/InstallRules create mode 100644 build/jam/MainBuildRules create mode 100644 build/jam/OverriddenJamRules create mode 100644 build/jam/PackageRules create mode 100644 build/jam/UserBuildConfig.sample create mode 100755 configure create mode 100644 data/icons/misc/Search create mode 100644 data/icons/status/Away create mode 100644 data/icons/status/Busy create mode 100644 data/icons/status/Offline create mode 100644 data/icons/status/Online create mode 100644 libs/Jamfile create mode 100644 libs/libinterface/BitmapMenuItem.cpp create mode 100644 libs/libinterface/BitmapMenuItem.h create mode 100644 libs/libinterface/BitmapUtils.cpp create mode 100644 libs/libinterface/BitmapUtils.h create mode 100644 libs/libinterface/BitmapView.cpp create mode 100644 libs/libinterface/BitmapView.h create mode 100644 libs/libinterface/Divider.cpp create mode 100644 libs/libinterface/Divider.h create mode 100644 libs/libinterface/Jamfile create mode 100644 libs/libinterface/NotifyingTextView.cpp create mode 100644 libs/libinterface/NotifyingTextView.h create mode 100644 libs/libinterface/PictureView.cpp create mode 100644 libs/libinterface/PictureView.h create mode 100644 libs/libjabber/Base64.cpp create mode 100644 libs/libjabber/Base64.h create mode 100644 libs/libjabber/JabberAgent.cpp create mode 100644 libs/libjabber/JabberAgent.h create mode 100644 libs/libjabber/JabberContact.cpp create mode 100644 libs/libjabber/JabberContact.h create mode 100644 libs/libjabber/JabberElement.cpp create mode 100644 libs/libjabber/JabberElement.h create mode 100644 libs/libjabber/JabberHandler.cpp create mode 100644 libs/libjabber/JabberHandler.h create mode 100644 libs/libjabber/JabberManager.h create mode 100644 libs/libjabber/JabberMessage.cpp create mode 100644 libs/libjabber/JabberMessage.h create mode 100644 libs/libjabber/JabberPlug.h create mode 100644 libs/libjabber/JabberPresence.cpp create mode 100644 libs/libjabber/JabberPresence.h create mode 100644 libs/libjabber/JabberRegistration.cpp create mode 100644 libs/libjabber/JabberRegistration.h create mode 100644 libs/libjabber/JabberSSLPlug.cpp create mode 100644 libs/libjabber/JabberSSLPlug.h create mode 100644 libs/libjabber/JabberSocketPlug.cpp create mode 100644 libs/libjabber/JabberSocketPlug.h create mode 100644 libs/libjabber/JabberVCard.cpp create mode 100644 libs/libjabber/JabberVCard.h create mode 100644 libs/libjabber/Jamfile create mode 100644 libs/libjabber/LICENSE create mode 100644 libs/libjabber/Logger.cpp create mode 100644 libs/libjabber/Logger.h create mode 100644 libs/libjabber/ObjectList.h create mode 100644 libs/libjabber/SHA1.cpp create mode 100644 libs/libjabber/SHA1.h create mode 100644 libs/libjabber/ServerHandler.h create mode 100644 libs/libjabber/States.h create mode 100644 libs/libjabber/VCardManager.cpp create mode 100644 libs/libjabber/VCardManager.h create mode 100644 libs/librunview/Emoconfig.cpp create mode 100644 libs/librunview/Emoconfig.h create mode 100644 libs/librunview/Emoticor.cpp create mode 100644 libs/librunview/Emoticor.h create mode 100644 libs/librunview/Jamfile create mode 100644 libs/librunview/NormalTextRender.h create mode 100644 libs/librunview/ObjectList.h create mode 100644 libs/librunview/RunView.cpp create mode 100644 libs/librunview/RunView.h create mode 100644 libs/librunview/SmileTextRender.h create mode 100644 libs/librunview/TextRender.h create mode 100644 libs/librunview/Theme.cpp create mode 100644 libs/librunview/Theme.h create mode 100644 libs/librunview/URLCrunch.cpp create mode 100644 libs/librunview/URLCrunch.h create mode 100644 libs/librunview/Utilities.cpp create mode 100644 libs/librunview/Utilities.h create mode 100644 libs/libsupport/Jamfile create mode 100644 libs/libsupport/Singleton.h create mode 100644 libs/private/IconUtils.h create mode 100644 libs/private/MenuPrivate.h create mode 100644 protocols/Jamfile create mode 100644 protocols/gtalk/GoogleTalk.cpp create mode 100644 protocols/gtalk/GoogleTalk.h create mode 100644 protocols/gtalk/Jamfile create mode 100644 protocols/gtalk/SettingsTemplate.rdef create mode 100644 protocols/gtalk/gtalk.rdef create mode 100644 protocols/gtalk/main.cpp create mode 100644 smileys/Jamfile create mode 100644 smileys/airplane.gif create mode 100644 smileys/angel_smile.gif create mode 100644 smileys/angry.gif create mode 100644 smileys/asl.gif create mode 100644 smileys/auto.gif create mode 100644 smileys/baring_teeth.gif create mode 100644 smileys/bat.gif create mode 100644 smileys/beer_mug.gif create mode 100644 smileys/black_sheep.gif create mode 100644 smileys/bowl.gif create mode 100644 smileys/brb.gif create mode 100644 smileys/broken_heart.gif create mode 100644 smileys/cake.gif create mode 100644 smileys/camera.gif create mode 100644 smileys/cat.gif create mode 100644 smileys/cigarette.gif create mode 100644 smileys/clock.gif create mode 100644 smileys/coffee.gif create mode 100644 smileys/computer.gif create mode 100644 smileys/confused.gif create mode 100644 smileys/console.gif create mode 100644 smileys/cry.gif create mode 100644 smileys/devil_smile.gif create mode 100644 smileys/dog.gif create mode 100644 smileys/dont_know.gif create mode 100644 smileys/dont_tell.gif create mode 100644 smileys/envelope.gif create mode 100644 smileys/film.gif create mode 100644 smileys/girl.gif create mode 100644 smileys/girl_hug.gif create mode 100644 smileys/guy.gif create mode 100644 smileys/guy_hug.gif create mode 100644 smileys/hahaha.gif create mode 100644 smileys/handcuffs.gif create mode 100644 smileys/heart.gif create mode 100644 smileys/island_palm.gif create mode 100644 smileys/kiss.gif create mode 100644 smileys/lightbulb.gif create mode 100644 smileys/lightning.gif create mode 100644 smileys/martini.gif create mode 100644 smileys/messenger.gif create mode 100644 smileys/mobile_phone.gif create mode 100644 smileys/money.gif create mode 100644 smileys/moon.gif create mode 100644 smileys/nerd.gif create mode 100644 smileys/note.gif create mode 100644 smileys/omg.gif create mode 100644 smileys/party.gif create mode 100644 smileys/phone.gif create mode 100644 smileys/pizaa.gif create mode 100644 smileys/pizza.gif create mode 100644 smileys/plate.gif create mode 100644 smileys/present.gif create mode 100644 smileys/rainbow.gif create mode 100644 smileys/red.gif create mode 100644 smileys/regular_smile.gif create mode 100644 smileys/regular_smiley.gif create mode 100644 smileys/roll.gif create mode 100644 smileys/rose.gif create mode 100644 smileys/ruler.gif create mode 100644 smileys/sad_smile.gif create mode 100644 smileys/sarcastic.gif create mode 100644 smileys/secret.gif create mode 100644 smileys/settings.xml create mode 100644 smileys/settings_svg.xml create mode 100644 smileys/shades.gif create mode 100644 smileys/sick.gif create mode 100644 smileys/sleepy.gif create mode 100644 smileys/smilec.gif create mode 100644 smileys/snail.gif create mode 100644 smileys/soccer.gif create mode 100644 smileys/star.gif create mode 100644 smileys/star2.gif create mode 100644 smileys/stormy.gif create mode 100644 smileys/sun.gif create mode 100644 smileys/svg/01.svg create mode 100644 smileys/svg/01.svg_ create mode 100644 smileys/svg/02.svg create mode 100644 smileys/svg/02.svg_ create mode 100644 smileys/svg/BeOS_logo.svg create mode 100644 smileys/svg/BeOS_logo.svg_ create mode 100644 smileys/svg/emoticon_1.svg create mode 100644 smileys/svg/emoticon_1.svg_ create mode 100644 smileys/svg/emoticon_2.svg create mode 100644 smileys/svg/emoticon_2.svg_ create mode 100644 smileys/svg/emoticon_3.svg create mode 100644 smileys/svg/emoticon_3.svg_ create mode 100644 smileys/svg/emoticon_4.svg create mode 100644 smileys/svg/emoticon_4.svg_ create mode 100644 smileys/svg/emoticon_5.svg create mode 100644 smileys/svg/emoticon_5.svg_ create mode 100644 smileys/svg/emoticon_6.svg create mode 100644 smileys/svg/emoticon_6.svg_ create mode 100644 smileys/svg/emoticon_7.svg create mode 100644 smileys/svg/emoticon_7.svg_ create mode 100644 smileys/svg/emoticon_8.svg create mode 100644 smileys/svg/emoticon_8.svg_ create mode 100644 smileys/svg/zeta-badge.svg create mode 100644 smileys/svg/zeta-badge.svg_ create mode 100644 smileys/teeth_smile.gif create mode 100644 smileys/thinking.gif create mode 100644 smileys/thumbs_down.gif create mode 100644 smileys/thumbs_up.gif create mode 100644 smileys/tongue_smile.gif create mode 100644 smileys/turtle.gif create mode 100644 smileys/umbrella.gif create mode 100644 smileys/what_smile.gif create mode 100644 smileys/wilted_rose.gif create mode 100644 smileys/wink_smile.gif create mode 100644 smileys/wu.gif diff --git a/Jamfile b/Jamfile new file mode 100644 index 0000000..6142f85 --- /dev/null +++ b/Jamfile @@ -0,0 +1,12 @@ +SubDir TOP ; + +# Include all the components +SubInclude TOP libs ; +SubInclude TOP application ; +SubInclude TOP protocols ; +SubInclude TOP smileys ; + +Distro distro ; +FullDistro fulldistro ; + +UninstallTarget $(APPS_DIRECTORY)/caya ; diff --git a/Jamrules b/Jamrules new file mode 100644 index 0000000..8a9d198 --- /dev/null +++ b/Jamrules @@ -0,0 +1,70 @@ +# The directories used by the build. +BUILD_DIR = [ FDirName $(TOP) build ] ; +JAM_DIR = [ FDirName $(BUILD_DIR) jam ] ; +SCRIPTS_DIR = [ FDirName $(JAM_DIR) scripts ] ; +GENERATED_DIR = [ FDirName $(TOP) generated ] ; +DISTRO_DIR = [ FDirName $(TOP) generated distro ] ; +FULL_DISTRO_DIR = [ FDirName $(TOP) generated fulldistro ] ; +PACKAGE_DIR = [ FDirName $(GENERATED_DIR) packages ] ; +PACKAGE_OBJECT_DIR = [ FDirName $(PACKAGE_DIR) objects ] ; + +##------------------------------------------------------------------- +## Defines +##------------------------------------------------------------------- +VERSION = 10 ; +DEFINES += VERSION=\"\\\"$(VERSION)\\\"\" ; +DEFINES += BUILD_DATE=\"\\\"$(JAMDATE)\\\"\" ; +CHGRP = ; +CHOWN = ; + +# Include BuildConfig generated by configure +{ + local buildConfig = [ Glob $(GENERATED_DIR) : BuildConfig ] ; + if $(buildConfig) { + LOCATE on BuildConfig = $(GENERATED_DIR) ; + include BuildConfig ; + } else { + Exit "Run ./configure first!" ; + } +} + +# Include UserBuildConfig +{ + local userBuildConfig = [ Glob $(JAM_DIR) : UserBuildConfig ] ; + if $(userBuildConfig) { + LOCATE on UserBuildConfig = $(JAM_DIR) ; + include UserBuildConfig ; + } +} + +# Cache files for header scanning and jamfile caching. +HCACHEFILE = header_cache ; +JCACHEFILE = jamfile_cache ; +LOCATE on $(HCACHEFILE) $(JCACHEFILE) = $(GENERATED_DIR) ; + +# Perform configuration checks +include [ FDirName $(JAM_DIR) CheckRules ] ; +CheckGccPlatform ; +CheckOpenSSL ; +if ! $(HAVE_OPENSSL) { +# Echo "** MSN, GoogleTalk and OSCAR protocols are disabled for lack of OpenSSL" ; +} +CheckLibYahoo2 ; +if ! $(HAVE_LIBYAHOO2) { +# Echo "** Yahoo protocol is disabled for lack of libyahoo2" ; +} +CheckInfoPopper ; +if ! $(HAVE_INFOPOPPER) { +# Echo "** im_infopopper client is disabled for lack of InfoPopper" ; +} + +# Include jam scripts +include [ FDirName $(JAM_DIR) HelperRules ] ; +include [ FDirName $(JAM_DIR) ConfigRules ] ; +include [ FDirName $(JAM_DIR) OverriddenJamRules ] ; +include [ FDirName $(JAM_DIR) MainBuildRules ] ; +include [ FDirName $(JAM_DIR) FileRules ] ; +include [ FDirName $(JAM_DIR) InstallRules ] ; +include [ FDirName $(JAM_DIR) PackageRules ] ; +include [ FDirName $(JAM_DIR) DistroRules ] ; +include [ FDirName $(JAM_DIR) BuildSettings ] ; diff --git a/application/Account.cpp b/application/Account.cpp new file mode 100644 index 0000000..0e11bf9 --- /dev/null +++ b/application/Account.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include "Account.h" + + +Account::Account(BHandler* msgTarget) +{ + BMessenger msgr(msgTarget); + fMessenger = msgr; +} + + +Account::~Account() +{ +} + + +status_t +Account::SendMessage(BMessage* message) +{ + // This is just an example of what can be done ;) + message->AddPointer("account", (void*)this); + return fMessenger.SendMessage(message); +} diff --git a/application/Account.h b/application/Account.h new file mode 100644 index 0000000..8f0ced3 --- /dev/null +++ b/application/Account.h @@ -0,0 +1,24 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ACCOUNT_H +#define _ACCOUNT_H + +#include +#include + +#include "CayaProtocol.h" + +class Account : public CayaProtocolMessengerInterface { +public: + Account(BHandler* msgTarget); + virtual ~Account(); + + virtual status_t SendMessage(BMessage* message); + +private: + BMessenger fMessenger; +}; + +#endif // _ACCOUNT_H diff --git a/application/AccountManager.cpp b/application/AccountManager.cpp new file mode 100644 index 0000000..6cbf365 --- /dev/null +++ b/application/AccountManager.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include "AccountManager.h" +#include "NotifyMessage.h" +#include "Server.h" +#include "TheApp.h" + +static AccountManager* fInstance = NULL; + + +AccountManager::AccountManager() + : fStatus(CAYA_OFFLINE) +{ + TheApp* theApp = reinterpret_cast(be_app); + RegisterObserver(theApp->GetMainWindow()); +} + + +AccountManager::~AccountManager() +{ + TheApp* theApp = reinterpret_cast(be_app); + UnregisterObserver(theApp->GetMainWindow()); +} + + +AccountManager* +AccountManager::Get() +{ + if (fInstance == NULL) + fInstance = new AccountManager(); + return fInstance; +} + + +void +AccountManager::SetNickname(BString nick) +{ + // Create message + BMessage* msg = new BMessage(IM_MESSAGE); + msg->AddInt32("im_what", IM_SET_NICKNAME); + msg->AddString("nick", nick); + + // Send message + TheApp* theApp = reinterpret_cast(be_app); + MainWindow* win = theApp->GetMainWindow(); + win->GetServer()->SendProtocolMessage(msg); +} + + +CayaStatus +AccountManager::Status() const +{ + return fStatus; +} + + +void +AccountManager::SetStatus(CayaStatus status, const char* str) +{ + if (fStatus != status) { + // Create status change message + BMessage* msg = new BMessage(IM_MESSAGE); + msg->AddInt32("im_what", IM_SET_STATUS); + msg->AddInt32("status", (int32)status); + if (str != NULL) + msg->AddString("message", str); + + // Send message + TheApp* theApp = reinterpret_cast(be_app); + MainWindow* win = theApp->GetMainWindow(); + win->GetServer()->SendProtocolMessage(msg); + + // Notify status change + fStatus = status; + NotifyInteger(INT_ACCOUNT_STATUS, (int32)fStatus); + } +} diff --git a/application/AccountManager.h b/application/AccountManager.h new file mode 100644 index 0000000..58ca8d5 --- /dev/null +++ b/application/AccountManager.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ACCOUNT_MANAGER_H +#define _ACCOUNT_MANAGER_H + +#include "CayaConstants.h" +#include "Notifier.h" + +class AccountManager : public Notifier { +public: + static AccountManager* Get(); + + void SetNickname(BString nick); + + CayaStatus Status() const; + void SetStatus(CayaStatus status, const char* str = NULL); + +private: + AccountManager(); + ~AccountManager(); + + CayaStatus fStatus; + //BObjectList fAccounts; +}; + +#endif // _ACCOUNT_MANAGER_H diff --git a/application/Caya.h b/application/Caya.h new file mode 100644 index 0000000..1a11816 --- /dev/null +++ b/application/Caya.h @@ -0,0 +1,10 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CAYA_H +#define _CAYA_H + +#define CAYA_SIGNATURE "application/x-vnd.xeD.Caya" + +#endif // _CAYA_H diff --git a/application/CayaConstants.h b/application/CayaConstants.h new file mode 100644 index 0000000..0f7b414 --- /dev/null +++ b/application/CayaConstants.h @@ -0,0 +1,138 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CAYA_CONSTANTS_H +#define _CAYA_CONSTANTS_H + +#include + +/* + * Color constants. + */ +const rgb_color CAYA_ORANGE_COLOR = {255, 186, 0, 255}; +const rgb_color CAYA_GREEN_COLOR = {43, 134, 43, 255}; +const rgb_color CAYA_RED_COLOR = {175, 1, 1, 255}; +const rgb_color CAYA_WHITE_COLOR = {255, 255, 255, 255}; +const rgb_color CAYA_BLACK_COLOR = {0, 0, 0, 255}; +const rgb_color CAYA_SELSTART_COLOR = {254, 150, 57}; +const rgb_color CAYA_SELEND_COLOR = {230, 113, 9}; + +/** + * What-codes for messages. + */ +enum message_what_codes { + // Used for all error messages + IM_ERROR = 'IMer', + + // Returned after a request has succeded + IM_ACTION_PERFORMED = 'IMok', + + // All client <> protocol communication uses the MESSAGE what-code. + IM_MESSAGE = 'IMme', + + IM_SERVER_BASED_CONTACT_LIST = 'IMsl' +}; + +/** + * Valid codes for im_what field. + */ +enum im_what_code { + // Request a server-side contact list from protocol + IM_GET_CONTACT_LIST = 1, + + // Send a message to a contact + IM_SEND_MESSAGE = 2, + + // Message has been sent to contact + IM_MESSAGE_SENT = 3, + + // Message received from contact + IM_MESSAGE_RECEIVED = 4, + + // Contact's status has changes + IM_STATUS_CHANGED = 5, + + // Server-side contact list received + IM_CONTACT_LIST = 6, + + // Change own nickname + IM_SET_NICKNAME = 7, + + // Change own status + IM_SET_STATUS = 8, + + // Retreive information on contact + IM_GET_CONTACT_INFO = 9, + + // Received information on contact + IM_CONTACT_INFO = 10, + + // Start listening to changes in these contact's statuses + IM_REGISTER_CONTACTS = 11, + + // Contact started typing + IM_CONTACT_STARTED_TYPING = 12, + + // Contact stopped typing + IM_CONTACT_STOPPED_TYPING = 13, + + // User started typing + IM_USER_STARTED_TYPING = 14, + + // User stopped typing + IM_USER_STOPPED_TYPING = 15, + + // Own status was chagned + IM_STATUS_SET = 16, + + // Authorization request received + IM_AUTH_REQUEST = 17, + + // Send authorization + IM_SEND_AUTH_ACK = 18, + + // Contact has been authorized + IM_CONTACT_AUTHORIZED = 19, + + // Request authorization from contact + IM_REQUEST_AUTH = 20, + + // Stop listening to status changes from these contacts + IM_UNREGISTER_CONTACTS = 21, + + // Progress message received, could be login sequence, file transfer etc... + IM_PROGRESS = 22, + + // Away message + GET_AWAY_MESSAGE = 23, + AWAY_MESSAGE = 24, + + // Protocols send this when they get a new avatar icon + IM_SET_AVATAR = 25, + + // Client get this when an avatar icon is changed + IM_AVATAR_CHANGED = 26, + + // Adding and removing contact from the server side list + IM_SERVER_LIST_ADD_CONTACT = 27, + IM_SERVER_LIST_REMOVED_CONTACT = 28, + + // Get account contact information + IM_OWN_CONTACT_INFO = 29, + + // These are forwarded to or from protocols + IM_SPECIAL_TO_PROTOCOL = 1000, + IM_SPECIAL_FROM_PROTOCOL = 1001 +}; + +enum CayaStatus { + CAYA_ONLINE = 1, + CAYA_AWAY = 2, + CAYA_EXTENDED_AWAY = 3, + CAYA_DO_NOT_DISTURB = 4, + CAYA_OFFLINE = 5, + CAYA_STATUSES = 6 +}; + +#endif // _CAYA_CONSTANTS_H diff --git a/application/CayaProtocol.h b/application/CayaProtocol.h new file mode 100644 index 0000000..923ba0e --- /dev/null +++ b/application/CayaProtocol.h @@ -0,0 +1,42 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef CayaProtocol_h +#define CayaProtocol_h + +#include + +class CayaProtocolMessengerInterface { + + public: + virtual status_t SendMessage(BMessage *message) = 0; + +}; + +class CayaProtocol +{ + public: + + // messenger + virtual status_t Init( CayaProtocolMessengerInterface * ) = 0; + + // called before unloading from memory + virtual status_t Shutdown() = 0; + + // process message + virtual status_t Process( BMessage * ) = 0; + + // Get name of protocol + virtual const char * GetSignature() = 0; + virtual const char * GetFriendlySignature() = 0; + + // settings changed + virtual status_t UpdateSettings( BMessage & ) = 0; + + // preferred encoding of messages + virtual uint32 GetEncoding() = 0; +}; + + +#endif diff --git a/application/CayaResources.h b/application/CayaResources.h new file mode 100644 index 0000000..8573ccf --- /dev/null +++ b/application/CayaResources.h @@ -0,0 +1,19 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CAYA_RESOURCES_H +#define _CAYA_RESOURCES_H + +enum { + kOnlineIcon = 10, + kAwayIcon = 11, + kBusyIcon = 12, + kOfflineIcon = 13, + + kSearchIcon = 100, + + kProtocolSettingsTemplate = 1000 +}; + +#endif // _CAYA_RESOURCES_H diff --git a/application/CayaUtils.cpp b/application/CayaUtils.cpp new file mode 100644 index 0000000..1373320 --- /dev/null +++ b/application/CayaUtils.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include + +#include "private/IconUtils.h" + +#include "CayaUtils.h" + + +const char* +CayaStatusToString(CayaStatus status) +{ + switch (status) { + case CAYA_ONLINE: + return "Available"; + case CAYA_OFFLINE: + return "Offline"; + case CAYA_AWAY: + return "Away"; + case CAYA_EXTENDED_AWAY: + return "Extended Away"; + case CAYA_DO_NOT_DISTURB: + return "Busy"; + default: + return NULL; + } +} + + +BBitmap* +RescaleBitmap(const BBitmap* src, int32 width, int32 height) +{ + width--; height--; + + if (!src || !src->IsValid()) + return NULL; + + BRect srcSize = src->Bounds(); + + if (height < 0) { + float srcProp = srcSize.Height() / srcSize.Width(); + height = (int32)(width * srcProp); + } + + BBitmap* res = new BBitmap(BRect(0, 0, width, height), src->ColorSpace()); + + float dx = (srcSize.Width() + 1) / (width + 1); + float dy = (srcSize.Height() + 1) / (height + 1); + uint8 bpp = (uint8)(src->BytesPerRow() / srcSize.Width()); + + int srcYOff = src->BytesPerRow(); + int dstYOff = res->BytesPerRow(); + + void* dstData = res->Bits(); + void* srcData = src->Bits(); + + for (int32 y = 0; y <= height; y++) { + void* dstRow = (void *)((uint32)dstData + (uint32)(y * dstYOff)); + void* srcRow = (void *)((uint32)srcData + ((uint32)(y * dy) * srcYOff)); + + for (int32 x = 0; x <= width; x++) + memcpy((void*)((uint32)dstRow + (x * bpp)), (void*)((uint32)srcRow + + ((uint32)(x * dx) * bpp)), bpp); + } + + return res; +} + + +extern "C" { + +status_t +our_image(image_info& image) +{ + team_id team = B_CURRENT_TEAM; + + int32 cookie = 0; + while (get_next_image_info(team, &cookie, &image) == B_OK) { + if ((char *)our_image >= (char *)image.text + && (char *)our_image <= (char *)image.text + image.text_size) + return B_OK; + } + + return B_ERROR; +} + +} diff --git a/application/CayaUtils.h b/application/CayaUtils.h new file mode 100644 index 0000000..eae2007 --- /dev/null +++ b/application/CayaUtils.h @@ -0,0 +1,22 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CAYA_UTILS_H +#define _CAYA_UTILS_H + +#include +#include + +#include "CayaConstants.h" + +class BBitmap; +class BResources; + +const char* CayaStatusToString(CayaStatus status); + +BBitmap* RescaleBitmap(const BBitmap* src, int32 width, int32 height); + +extern "C" status_t our_image(image_info& image); + +#endif // _CAYA_UTILS_H diff --git a/application/ChatWindow.cpp b/application/ChatWindow.cpp new file mode 100644 index 0000000..dc51590 --- /dev/null +++ b/application/ChatWindow.cpp @@ -0,0 +1,248 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ChatWindow.h" +#include "ContactLinker.h" +#include "EditingFilter.h" +#include "CayaConstants.h" +#include "CayaRenderView.h" +#include "NotifyMessage.h" + +const int32 kCloseWindow = 'clwn'; +const int32 kChat = 'chat'; + + +ChatWindow::ChatWindow(ContactLinker* cl) + : BWindow(BRect(200, 200, 500, 500), + cl->GetName().String(), B_DOCUMENT_WINDOW, 0), + fContactLinker(cl) +{ + fReceiveView = new CayaRenderView("fReceiveView"); + fReceiveView->SetOtherNick(cl->GetName()); + BScrollView* scrollViewReceive = new BScrollView("scrollviewR", fReceiveView, + B_WILL_DRAW, false, true); + + fSendView = new BTextView("fReceiveView"); + BScrollView* scrollViewSend = new BScrollView("scrollviewS", fSendView, + B_WILL_DRAW, false, true); + fSendView->SetWordWrap(true); + AddCommonFilter(new EditingFilter(fSendView)); + fSendView->MakeFocus(true); + + SetLayout(new BGroupLayout(B_HORIZONTAL)); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 10) + .Add(scrollViewReceive, 2) + .Add(scrollViewSend) + .SetInsets(5, 5, 5, 5) + ); + + MoveTo(BAlert::AlertPosition(Bounds().Width(), Bounds().Height() / 2)); + + fSendView->MakeFocus(true); + +} + + +bool +ChatWindow::QuitRequested() +{ + BMessage msg(kCloseWindow); + msg.AddString("id", fContactLinker->GetId()); + fContactLinker->GetMessenger().SendMessage(&msg); + return false; +} + + +void +ChatWindow::MessageReceived(BMessage* message) +{ + switch(message->what) { + case kChat: + { + BString message = fSendView->Text(); + if (message == "") + return; + + fReceiveView->AppendOwnMessage(message.String()); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_SEND_MESSAGE); + msg.AddString("id", fContactLinker->GetId()); + msg.AddString("message", message); + fContactLinker->GetMessenger().SendMessage(&msg); + + fSendView->SetText(""); + break; + } + case IM_MESSAGE: + ImMessage(message); + break; + default: + BWindow::MessageReceived(message); + break; + } +} + + +void +ChatWindow::ImMessage(BMessage* msg) +{ + int32 im_what = msg->FindInt32("im_what"); + switch (im_what) { + case IM_MESSAGE_RECEIVED: + { + BString message = msg->FindString("message"); + fReceiveView->AppendOtherMessage(message.String()); + break; + } + case IM_STATUS_CHANGED: + { +#if 0 + int32 status; + + if (msg->FindInt32("status", &status) != B_OK) + return; + + BString id = msg->FindString("id"); + + if (id != "" && status >= CAYA_ONLINE) { + bool found = false; + BStringItem *item = fRosterMap.ValueFor(id,&found); + + if (!found) { + item = new BStringItem(id.String()); + item->SetHeight(50.0); + listView->AddItem(item); + fRosterMap.AddItem(id, item); + } else { + bool itemPresent = listView->HasItem(item); + if (status == CAYA_OFFLINE) { + //remove from list. (for now) + if (itemPresent) + listView->RemoveItem(item); + } else { + if(!itemPresent) + listView->AddItem(item); + } + } + + UpdateListItem(item); + } +#endif + break; + } + case IM_CONTACT_INFO: + { +#if 0 + BString id = msg->FindString("id"); + BString fullName = msg->FindString("nick"); + if (id != "" && fullName != "") { + bool found = false; + BStringItem *item = fRosterMap.ValueFor(id,&found); + if (!found) { + item = new BStringItem(id.String()); + item->SetHeight(50.0); + fRosterMap.AddItem(id, item); + } + + item->SetText(fullName); + UpdateListItem(item); + } +#endif + break; + } + default: + break; + } +} + +void +ChatWindow::ObserveString(int32 what, BString str) +{ + switch(what) { + case STR_CONTACT_NAME: + if (Lock()){ + SetTitle(str); + fReceiveView->SetOtherNick(str); + Unlock(); + } + break; + case STR_PERSONAL_STATUS: + break; + } +} + + +void +ChatWindow::ObservePointer(int32 what, void* ptr) +{ + switch (what) { + case PTR_AVATAR_BITMAP: + break; + } +} + + +void +ChatWindow::ObserveInteger(int32 what, int32 val) +{ + switch (what) { + case INT_CONTACT_STATUS: + if (Lock()) { + AppendStatus((CayaStatus)val); + Unlock(); + } + break; + } +} + + +void +ChatWindow::AppendStatus(CayaStatus status) +{ + BString message(fContactLinker->GetName()); + + switch (status) { + case CAYA_ONLINE: + message << " is available"; + break; + case CAYA_EXTENDED_AWAY: + case CAYA_AWAY: + message << " is away"; + break; + case CAYA_DO_NOT_DISTURB: + message << " is busy, please do not disturb!"; + break; + case CAYA_OFFLINE: + message << " is offline"; + break; + default: + break; + } + + fReceiveView->Append(message.String(), COL_TEXT, COL_TEXT, R_TEXT); + fReceiveView->Append("\n", COL_TEXT, COL_TEXT, R_TEXT); + fReceiveView->ScrollToSelection(); +} diff --git a/application/ChatWindow.h b/application/ChatWindow.h new file mode 100644 index 0000000..0069d93 --- /dev/null +++ b/application/ChatWindow.h @@ -0,0 +1,40 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ChatWindow_H_ +#define ChatWindow_H_ + +#include +#include +#include "Observer.h" +#include "CayaConstants.h" + +class ContactLinker; +class CayaRenderView; + +class ChatWindow: public BWindow , public Observer +{ + + public: + ChatWindow(ContactLinker* cl); + virtual void MessageReceived(BMessage* message); + void ImMessage(BMessage *msg); + virtual bool QuitRequested(); + + void ObserveString(int32 what, BString str); + void ObservePointer(int32 what, void* ptr); + void ObserveInteger(int32 what, int32 val); + void AppendStatus(CayaStatus status); + + private: + + BTextView* fSendView; + ContactLinker* fContactLinker; + CayaRenderView *fReceiveView; + +}; + +#endif + +//-- diff --git a/application/ContactLinker.cpp b/application/ContactLinker.cpp new file mode 100644 index 0000000..3746549 --- /dev/null +++ b/application/ContactLinker.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include + +#include "ChatWindow.h" +#include "ContactLinker.h" +#include "ContactPopUp.h" +#include "NotifyMessage.h" +#include "ProtocolManager.h" +#include "RosterItem.h" +#include "WindowsManager.h" + + +ContactLinker::ContactLinker(BString id, BMessenger msgn) + : fChatWindow(NULL), + fID(id), + fName(id), + fMessenger(msgn), + fStatus(CAYA_OFFLINE), + fPopUp(NULL) +{ + // Create the roster item and register it as observer + fRosterItem = new RosterItem(id.String(), this); + RegisterObserver(fRosterItem); + + // By default we use protocol icon as avatar icon + fAvatarBitmap = ProtocolManager::Get()->GetProtocolIcon("gtalk"); +} + + +ChatWindow* +ContactLinker::GetChatWindow() +{ + if (fChatWindow == NULL) + CreateChatWindow(); + return fChatWindow; +} + + +void +ContactLinker::DeleteWindow() +{ + if (fChatWindow != NULL) { + if (fChatWindow->Lock()) { + UnregisterObserver(fChatWindow); + fChatWindow->Quit(); + fChatWindow = NULL; + } + } +} + + +void +ContactLinker::ShowWindow() +{ + if (fChatWindow == NULL) + CreateChatWindow(); + fChatWindow->SetWorkspaces(B_CURRENT_WORKSPACE); + if (fChatWindow->IsHidden()) + fChatWindow->Show(); + fChatWindow->Activate(true); +} + + +void +ContactLinker::HideWindow() +{ + if ((fChatWindow != NULL) && !fChatWindow->IsHidden()) + fChatWindow->Hide(); +} + + +void +ContactLinker::ShowPopUp(BPoint where) +{ + if (fPopUp == NULL) { + fPopUp = new ContactPopUp(this); + RegisterObserver(fPopUp); + } + + fPopUp->Show(); + fPopUp->MoveTo(where); +} + + +void +ContactLinker::HidePopUp() +{ + if ((fPopUp != NULL) && !fPopUp->IsHidden()) + fPopUp->Hide(); +} + + +void +ContactLinker::DeletePopUp() +{ + if (fPopUp == NULL) + return; + + if (fPopUp->Lock()) { + UnregisterObserver(fPopUp); + fPopUp->Quit(); + fPopUp = NULL; + } +} + + +void +ContactLinker::SetNotifyName(BString name) +{ + if (fName.Compare(name) != 0) { + fName = name; + NotifyString(STR_CONTACT_NAME, name); + } +} + + +void +ContactLinker::SetNotifyAvatarBitmap(BBitmap* bitmap) +{ + if ((fAvatarBitmap != bitmap) && (bitmap != NULL)) { + fAvatarBitmap = bitmap; + NotifyPointer(PTR_AVATAR_BITMAP, (void*)bitmap); + } +} + + +void +ContactLinker::SetNotifyStatus(CayaStatus status) +{ + if (fStatus != status) { + fStatus = status; + NotifyInteger(INT_CONTACT_STATUS, (int32)fStatus); + } +} + + +void +ContactLinker::SetNotifyPersonalStatus(BString personalStatus) +{ + if (fPersonalStatus.Compare(personalStatus) != 0) { + fPersonalStatus = personalStatus; + NotifyString(STR_PERSONAL_STATUS, personalStatus); + } +} + + +void +ContactLinker::CreateChatWindow() +{ + fChatWindow = new ChatWindow(this); + WindowsManager::Get()->RelocateWindow(fChatWindow); + RegisterObserver(fChatWindow); +} diff --git a/application/ContactLinker.h b/application/ContactLinker.h new file mode 100644 index 0000000..c1b9b7a --- /dev/null +++ b/application/ContactLinker.h @@ -0,0 +1,64 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CONTACT_LINKER_H_ +#define _CONTACT_LINKER_H_ + +#include +#include +#include + +#include "Notifier.h" +#include "CayaConstants.h" + +class BBitmap; + +class ChatWindow; +class ContactPopUp; +class RosterItem; + +class ContactLinker : public Notifier { +public: + ContactLinker(BString id, BMessenger msgn); + + ChatWindow* GetChatWindow(); + void DeleteWindow(); + + void ShowWindow(); + void HideWindow(); + + void ShowPopUp(BPoint where); + void DeletePopUp(); + void HidePopUp(); + + RosterItem* GetRosterItem() { return fRosterItem; } + + BString GetId() { return fID; } + + BMessenger GetMessenger() { return fMessenger; } + + BString GetName() { return fName; } + BBitmap* AvatarBitmap() { return fAvatarBitmap; } + + void SetNotifyName(BString name); + void SetNotifyAvatarBitmap(BBitmap* bitmap); + void SetNotifyStatus(CayaStatus status); + void SetNotifyPersonalStatus(BString personalStatus); + +private: + void CreateChatWindow(); + + RosterItem* fRosterItem; + ChatWindow* fChatWindow; + BMessenger fMessenger; + + BString fID; + BString fName; + BString fPersonalStatus; + BBitmap* fAvatarBitmap; + CayaStatus fStatus; + ContactPopUp* fPopUp; +}; + +#endif // _CONTACT_LINKER_H_ diff --git a/application/EditingFilter.cpp b/application/EditingFilter.cpp new file mode 100644 index 0000000..5605ae0 --- /dev/null +++ b/application/EditingFilter.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include +#include +#include + +#include "EditingFilter.h" + + +EditingFilter::EditingFilter(BTextView* view) + : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, B_KEY_DOWN, NULL), + _view(view) +{ +} + + +filter_result +EditingFilter::Filter(BMessage* message, BHandler** target) +{ + int32 modifiers; + + int8 byte; + message->FindInt8("byte", &byte); + + // If we have modifiers but none are the Alt key + if (message->FindInt32("modifiers", &modifiers)) + return B_DISPATCH_MESSAGE; + + // If the Alt key jives with the command_enter status + if ((modifiers & B_COMMAND_KEY) != 0 && byte == B_ENTER) { + _view->Insert("\n"); + return B_SKIP_MESSAGE; + } else if ((modifiers & B_COMMAND_KEY) == 0 && byte == B_ENTER) { + _view->Window()->PostMessage('chat'); + return B_SKIP_MESSAGE; + } + + return B_DISPATCH_MESSAGE; +} diff --git a/application/EditingFilter.h b/application/EditingFilter.h new file mode 100644 index 0000000..0f25744 --- /dev/null +++ b/application/EditingFilter.h @@ -0,0 +1,21 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef EDITING_FILTER_H +#define EDITING_FILTER_H + +#include +#include + +class EditingFilter : public BMessageFilter { +public: + EditingFilter(BTextView *view); + + virtual filter_result Filter(BMessage *message, BHandler **target); + +private: + BTextView *_view; +}; +#endif + diff --git a/application/ImageCache.cpp b/application/ImageCache.cpp new file mode 100644 index 0000000..371c980 --- /dev/null +++ b/application/ImageCache.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include "ImageCache.h" + +#include +#include +#include +#include + +ImageCache *ImageCache::m_instance = NULL; + + +ImageCache::ImageCache() +{ +} + + +ImageCache::~ImageCache() +{ + while(m_bitmaps.CountItems()) { + BBitmap* bit=m_bitmaps.ValueFor(0); + delete bit; + } +} + + +BBitmap* +ImageCache::GetImage(BString which, BString name) +{ + if (m_instance == NULL) + m_instance = new ImageCache(); + + // Loads the bitmap if found + bool found; + BBitmap* bitmap = m_instance->m_bitmaps.ValueFor(name, &found); + + if (!found) { + bitmap = LoadImage(which.String(), name.String()); + if (bitmap) + m_instance->m_bitmaps.AddItem(name, bitmap); + return bitmap; + } else + return bitmap; + return NULL; +} + + +void +ImageCache::AddImage(BString name, BBitmap* which) +{ + if (m_instance == NULL) + m_instance = new ImageCache(); + + m_instance->m_bitmaps.AddItem(name, which); +} + + +void +ImageCache::DeleteImage(BString name) +{ + if (m_instance == NULL) + m_instance = new ImageCache(); + + BBitmap* bitmap = m_instance->m_bitmaps.ValueFor(name); + if (bitmap){ + m_instance->m_bitmaps.RemoveItemFor(name); + delete bitmap; + } +} + + +void +ImageCache::Release() +{ + if (m_instance != NULL) { + delete m_instance; + m_instance = NULL; + } +} + + +BBitmap* +ImageCache::LoadImage(const char* fullName, const char* shortName) +{ + BBitmap* bitmap = BTranslationUtils::GetBitmap(fullName); + if (!bitmap) + bitmap = BTranslationUtils::GetBitmap('PNG ', shortName); + + if (!bitmap) + printf("ImageCache: Can't load bitmap! %s\n",fullName); + return bitmap; +} diff --git a/application/ImageCache.h b/application/ImageCache.h new file mode 100644 index 0000000..2496571 --- /dev/null +++ b/application/ImageCache.h @@ -0,0 +1,56 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ImageCache_H +#define ImageCache_H + + /** + * ImageCache. + * @author Andrea Anzani. + */ + +class BBitmap; + +#include +#include +#include "KeyMap.h" + +class ImageCache +{ + +protected: // Constructor/Destructor + + ImageCache(); + + ~ImageCache(); + +public: // Operations + + /** Returns the image corresponding to the which constant */ + static BBitmap * GetImage( BString fullPath , BString symbolicName); + + + static void AddImage(BString name,BBitmap* which); + static void DeleteImage(BString name); + + /** Frees the singleton instance of the cache; + Call this when app quits + */ + static void Release(); + +private: + + static BBitmap * LoadImage( const char *resourceName,const char *); + // Class Data + + static ImageCache * m_instance; + +private: // Instance Data + + + KeyMap m_bitmaps; + +}; + +#endif /* __C_ImageCache_H__ */ diff --git a/application/Jamfile b/application/Jamfile new file mode 100644 index 0000000..dac368a --- /dev/null +++ b/application/Jamfile @@ -0,0 +1,56 @@ +SubDir TOP application ; + +SubDirSysHdrs [ FDirName $(TOP) ] ; +SubDirSysHdrs [ FDirName $(TOP) libs ] ; +SubDirSysHdrs [ FDirName $(TOP) libs libjabber ] ; +SubDirSysHdrs [ FDirName $(TOP) libs librunview ] ; +SubDirSysHdrs [ FDirName $(TOP) libs libinterface ] ; +SubDirSysHdrs [ FDirName $(OPENSSL_INCLUDE_DIR) ] ; + +SEARCH_SOURCE += [ FDirName $(TOP) application preferences ] ; +SEARCH_SOURCE += [ FDirName $(TOP) application views ] ; + +Application caya : + Account.cpp + AccountManager.cpp + CayaUtils.cpp + ChatWindow.cpp + ContactLinker.cpp + EditingFilter.cpp + ImageCache.cpp + LooperCayaProtocol.cpp + Main.cpp + MainWindow.cpp + Notifier.cpp + ProtocolManager.cpp + ProtocolSettings.cpp + Server.cpp + TheApp.cpp + WindowsManager.cpp + + # preferences + AccountListItem.cpp + PreferencesDialog.cpp + PreferencesAccounts.cpp + + # views + ContactPopUp.cpp + NicknameTextControl.cpp + RosterItem.cpp + RosterListView.cpp + StatusMenuItem.cpp + StatusView.cpp + CayaRenderView.cpp + : be $(TARGET_LIBSTDC++) network translation expat + librunview.a libinterface.a libjabber.a + ssl crypto + : caya.rdef +; + +Depends caya : libjabber.a ; +Depends caya : librunview.a ; +Depends caya : libinterface.a ; + +LINKFLAGS on caya += -L$(OPENSSL_LIBRARY_DIR) ; + +InstallBin $(APPS_DIRECTORY)/caya : caya ; diff --git a/application/KeyMap.h b/application/KeyMap.h new file mode 100644 index 0000000..2d7421f --- /dev/null +++ b/application/KeyMap.h @@ -0,0 +1,117 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEY_MAP_H +#define _KEY_MAP_H + +#include + +#include +#include + +template +class KeyMap { +public: + uint32 CountItems(); + + void AddItem(KEY k, TYPE t); + + TYPE ValueFor(KEY, bool* found = NULL); + + void RemoveItemAt(int32 position); + void RemoveItemFor(KEY); + + TYPE ValueAt(int32 position); + KEY KeyAt(int32 position); + + BList* Items(); + +private: + std::map fMap; + typedef typename std::map::iterator fIter; +}; + + +template +uint32 KeyMap::CountItems() +{ + return fMap.size(); +} + + +template +void KeyMap::AddItem(KEY k, TYPE t) +{ + fMap[k] = t; +} + + +template +TYPE KeyMap::ValueFor(KEY k, bool* found) +{ + fIter i = fMap.find(k); + + if (found) { + if (i == fMap.end()) + *found = false; + else + *found = true; + } + + if (i == fMap.end()) + return NULL; + return i->second; +} + + +template +void KeyMap::RemoveItemAt(int32 position) +{ + fIter i = fMap.begin(); + std::advance(i, position); + fMap.erase(i->first); +} + + +template +void KeyMap::RemoveItemFor(KEY k) +{ + fMap.erase(k); +} + + +template +TYPE KeyMap::ValueAt(int32 position) +{ + fIter i = fMap.begin(); + std::advance(i, position); + if (i == fMap.end()) + return NULL; + return i->second; +} + + +template +KEY KeyMap::KeyAt(int32 position) +{ + fIter i = fMap.begin(); + std::advance(i, position); + if (i == fMap.end()) + return NULL; + return i->first; +} + + +template +BList* KeyMap::Items() +{ + BList* list = new BList(); + + for (fIter i = fMap.begin(); i != fMap.end(); ++i) + list->AddItem(i->second); + + return list; +} + +#endif // _KEY_MAP_H diff --git a/application/LooperCayaProtocol.cpp b/application/LooperCayaProtocol.cpp new file mode 100644 index 0000000..9857352 --- /dev/null +++ b/application/LooperCayaProtocol.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include + +#include "LooperCayaProtocol.h" + + +LooperCayaProtocol::LooperCayaProtocol(CayaProtocol* protocol) + : BLooper(), + fProtocol(protocol) +{ + BString name("CayaProcol - "); + name << protocol->GetFriendlySignature(); + SetName(name.String()); + Run(); +} + + +void +LooperCayaProtocol::MessageReceived(BMessage* msg) +{ + if (Protocol()->Process(msg) != B_OK) + BLooper::MessageReceived(msg); +} + + +CayaProtocol* +LooperCayaProtocol::Protocol() +{ + return fProtocol; +} diff --git a/application/LooperCayaProtocol.h b/application/LooperCayaProtocol.h new file mode 100644 index 0000000..7db5552 --- /dev/null +++ b/application/LooperCayaProtocol.h @@ -0,0 +1,25 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef LooperCayaProtocol_h +#define LooperCayaProtocol_h + +#include +#include "CayaProtocol.h" + +class LooperCayaProtocol : public BLooper +{ + public: + LooperCayaProtocol(CayaProtocol* protocol); + + void MessageReceived(BMessage* msg); + + CayaProtocol* Protocol(); + + private: + CayaProtocol* fProtocol; +}; + + +#endif diff --git a/application/Main.cpp b/application/Main.cpp new file mode 100644 index 0000000..0b72571 --- /dev/null +++ b/application/Main.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include "TheApp.h" + +int +main(int argc, char* argv[]) +{ + TheApp app; + app.Run(); + + return 0; +} diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp new file mode 100644 index 0000000..3493b16 --- /dev/null +++ b/application/MainWindow.cpp @@ -0,0 +1,314 @@ +/* + * Copyright 2009-2010, Andrea Anzani. All rights reserved. + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CayaConstants.h" +#include "NotifyMessage.h" +#include "MainWindow.h" +#include "PreferencesDialog.h" +#include "RosterItem.h" +#include "RosterListView.h" +#include "Server.h" +#include "StatusView.h" + +const int32 kLogin = 'LOGI'; +const int32 kSearchContact = 'SRCH'; +const int32 kPreferences = 'PRFS'; + + +MainWindow::MainWindow() : + BWindow(BRect(0, 0, 300, 400), "Caya", B_DOCUMENT_WINDOW, 0) +{ + SetLayout(fStack = new BCardLayout()); + + BBox* loginView = new BBox("loginView"); + + BButton* login = new BButton(BRect(294.0, 302.0, 392.0, 328.0), "login", + "Login", new BMessage(kLogin), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT); + + loginView->SetLayout(new BGroupLayout(B_HORIZONTAL)); + loginView->AddChild(BGroupLayoutBuilder(B_VERTICAL, 5) + .Add(BGridLayoutBuilder(10, 10) + .Add(new BStringView("label_u", "Username"), 0, 0) + .Add(fUsername = new BTextControl("username", NULL, NULL, NULL), 1, 0) + .Add(new BStringView("label_p", "Password"), 0, 1) + .Add(fPassword = new BTextControl("password", NULL, NULL, + new BMessage(kLogin)), 1, 1), 2) + .Add(login, 3) + ); + + fStack->AddView(loginView); + + fStatusView = new StatusView("statusView"); + + BTextControl* searchBox = new BTextControl("searchBox", NULL, NULL, + new BMessage(kSearchContact)); + + BBox* rosterView = new BBox("rosterView"); + + fListView = new RosterListView("buddyView"); + fListView->SetInvocationMessage(new BMessage(OPEN_WINDOW)); + BScrollView* scrollView = new BScrollView("scrollview", fListView, + B_WILL_DRAW, false, true); + + BButton* wrench = new BButton("wrench", new BMessage(kPreferences)); + + rosterView->SetLayout(new BGroupLayout(B_HORIZONTAL)); + rosterView->AddChild(BGroupLayoutBuilder(B_HORIZONTAL) + .AddGroup(B_VERTICAL) + .AddGroup(B_HORIZONTAL) + .AddGroup(B_VERTICAL) + .Add(fStatusView) + .Add(searchBox) + .End() + .Add(wrench) + .End() + .Add(scrollView) + .End() + .SetInsets(5, 5, 5, 10) + ); + + fStack->AddView(rosterView); + fStack->SetVisibleItem((long)0); + + AddShortcut('a', B_COMMAND_KEY, new BMessage(B_ABOUT_REQUESTED)); + MoveTo(BAlert::AlertPosition(Bounds().Width(), Bounds().Height() / 2)); + + fPassword->TextView()->HideTyping(true); + fUsername->MakeFocus(true); + + fSrv = new Server(this); + AddFilter(fSrv); + + CenterOnScreen(); +} + + +bool +MainWindow::QuitRequested() +{ + fListView->MakeEmpty(); + fSrv->Quit(); + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + + +void +MainWindow::MessageReceived(BMessage* message) +{ + switch(message->what) { + case kLogin: + { + BString username(fUsername->Text()); + BString password(fPassword->Text()); + if (username == "" || password == "") + return; + + BMessage config; + config.AddString("username", username); + config.AddString("password", password); + config.AddString("resource", "caya"); + + fSrv->UpdateSettings(config); + fSrv->Login(); + + fStack->SetVisibleItem((long)1); + break; + } + case kSearchContact: + { + void* control = NULL; + if (message->FindPointer("source", &control) != B_OK) + return; + + BTextControl* searchBox = static_cast(control); + if (searchBox == NULL) + return; + + RosterMap map = fSrv->RosterItems(); + for (uint32 i = 0; i < map.CountItems(); i++) { + ContactLinker* linker = map.ValueAt(i); + RosterItem* item = linker->GetRosterItem(); + + // If the search filter has been deleted show all the items, + // otherwise remove the item in order to show only items + // that matches the search criteria + if (strcmp(searchBox->Text(), "") == 0) + AddItem(item); + else if (linker->GetName().IFindFirst(searchBox->Text()) == B_ERROR) + RemoveItem(item); + else + AddItem(item); + UpdateListItem(item); + } + break; + } + case kPreferences: { + PreferencesDialog* dialog = new PreferencesDialog(); + dialog->Show(); + break; + } + case IM_MESSAGE: + ImMessage(message); + break; + case IM_ERROR: + ImError(message); + break; + default: + BWindow::MessageReceived(message); + break; + } +} + +void +MainWindow::ImError(BMessage* msg) +{ + //FIXME: better error handling.. + BAlert* alert = new BAlert("Error", msg->FindString("error"), "Ouch!"); + alert->Go(); + fStack->SetVisibleItem((long)0); +} + +void +MainWindow::ImMessage(BMessage* msg) +{ + int32 im_what = msg->FindInt32("im_what"); + switch(im_what) { + case IM_OWN_CONTACT_INFO: + { + fStatusView->SetName(msg->FindString("nick")); + + entry_ref ref; + if (msg->FindRef("ref", &ref) == B_OK) { + BBitmap* bitmap = BTranslationUtils::GetBitmap(&ref); + fStatusView->SetAvatar(bitmap); + } + break; + } + case IM_STATUS_CHANGED: + { + int32 status; + + if (msg->FindInt32("status", &status) != B_OK) + return; + + RosterItem* rosterItem = fSrv->RosterItemForId(msg->FindString("id")); + + if (rosterItem) { + // Add or remove item + UpdateListItem(rosterItem); + switch (status) { + case CAYA_OFFLINE: + if (HasItem(rosterItem)) + RemoveItem(rosterItem); + return; + default: + if (!HasItem(rosterItem)) + AddItem(rosterItem); + break; + } + UpdateListItem(rosterItem); + + // Sort list view again + fListView->Sort(); + } + break; + } + case IM_AVATAR_CHANGED: + case IM_CONTACT_INFO: + { + RosterItem* rosterItem = fSrv->RosterItemForId(msg->FindString("id")); + if (rosterItem) + UpdateListItem(rosterItem); + break; + } + } +} + + +void +MainWindow::ObserveInteger(int32 what, int32 val) +{ + switch (what) { + case INT_ACCOUNT_STATUS: + fStatusView->SetStatus((CayaStatus)val); + break; + } +} + + +void +MainWindow::UpdateListItem(RosterItem* item) +{ + if (fListView->HasItem(item)) + fListView->InvalidateItem(fListView->IndexOf(item)); +} + + +int32 +MainWindow::CountItems() const +{ + return fListView->CountItems(); +} + + +RosterItem* +MainWindow::ItemAt(int index) +{ + return dynamic_cast(fListView->ItemAt(index)); +} + + +void +MainWindow::AddItem(RosterItem* item) +{ + // Don't add offline items and avoid duplicates + if ((item->Status() == CAYA_OFFLINE) || HasItem(item)) + return; + + // Add item and sort + fListView->AddItem(item); + fListView->Sort(); +} + + +bool +MainWindow::HasItem(RosterItem* item) +{ + return fListView->HasItem(item); +} + + +void +MainWindow::RemoveItem(RosterItem* item) +{ + // Remove item and sort + fListView->RemoveItem(item); + fListView->Sort(); +} diff --git a/application/MainWindow.h b/application/MainWindow.h new file mode 100644 index 0000000..b5de6fe --- /dev/null +++ b/application/MainWindow.h @@ -0,0 +1,54 @@ +/* + * Copyright 2009-2010, Andrea Anzani. All rights reserved. + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _MAIN_WINDOW_H +#define _MAIN_WINDOW_H + +#include + +#include "Observer.h" + +class BCardLayout; +class BTextControl; + +class Server; +class StatusView; +class RosterListView; +class RosterItem; + +#define OPEN_WINDOW 'opwn' +#define CLOSE_WINDOW 'clwn' + +class MainWindow: public BWindow, public Observer { +public: + MainWindow(); + + virtual void MessageReceived(BMessage* message); + void ImMessage(BMessage* msg); + void ImError(BMessage* msg); + virtual bool QuitRequested(); + + void ObserveInteger(int32 what, int32 val); + + Server* GetServer() const { return fSrv; } + + void UpdateListItem(RosterItem* item); + + int32 CountItems() const; + RosterItem* ItemAt(int index); + void AddItem(RosterItem*); + bool HasItem(RosterItem*); + void RemoveItem(RosterItem*); + +private: + StatusView* fStatusView; + RosterListView* fListView; + BCardLayout* fStack; + BTextControl* fUsername; + BTextControl* fPassword; + Server* fSrv; +}; + +#endif // _MAIN_WINDOW_H diff --git a/application/Notifier.cpp b/application/Notifier.cpp new file mode 100644 index 0000000..2e50ac5 --- /dev/null +++ b/application/Notifier.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include "Notifier.h" +#include "Observer.h" + + +void +Notifier::RegisterObserver(Observer* obs) +{ + if (!fObserverList.HasItem(obs)) + fObserverList.AddItem(obs); +} + + +void +Notifier::UnregisterObserver(Observer* obs) +{ + if (fObserverList.HasItem(obs)) + fObserverList.RemoveItem(obs, false); +} + + +void +Notifier::NotifyString(int32 what, BString str) +{ + for (int i = 0; i < fObserverList.CountItems(); i++) + fObserverList.ItemAt(i)->ObserveString(what, str); +} + + +void +Notifier::NotifyInteger(int32 what, int32 value) +{ + for (int i = 0; i < fObserverList.CountItems(); i++) + fObserverList.ItemAt(i)->ObserveInteger(what, value); +} + +void +Notifier::NotifyPointer(int32 what, void* ptr) +{ + for (int i = 0; i < fObserverList.CountItems(); i++) + fObserverList.ItemAt(i)->ObservePointer(what, ptr); +} diff --git a/application/Notifier.h b/application/Notifier.h new file mode 100644 index 0000000..8d4372a --- /dev/null +++ b/application/Notifier.h @@ -0,0 +1,29 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef Notifier_h_ +#define Notifier_h_ + +#include + +#include "ObjectList.h" +#include "Observer.h" + +class Notifier +{ + public: + + void RegisterObserver(Observer*); + void UnregisterObserver(Observer*); + + void NotifyString(int32 what, BString str); + void NotifyInteger(int32 what, int32 value); + void NotifyPointer(int32 what, void* ptr); + + private: + + BObjectList fObserverList; + +}; +#endif diff --git a/application/NotifyMessage.h b/application/NotifyMessage.h new file mode 100644 index 0000000..7c1963c --- /dev/null +++ b/application/NotifyMessage.h @@ -0,0 +1,18 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _NOTIFY_MESSAGE_H +#define _NOTIFY_MESSAGE_H + +enum { + STR_CONTACT_NAME, + STR_PERSONAL_STATUS, + + PTR_AVATAR_BITMAP, + + INT_ACCOUNT_STATUS, + INT_CONTACT_STATUS +}; + +#endif // _NOTIFY_MESSAGE_H diff --git a/application/Observer.h b/application/Observer.h new file mode 100644 index 0000000..e98f21d --- /dev/null +++ b/application/Observer.h @@ -0,0 +1,19 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef Observer_h_ +#define Observer_h_ + +#include + +class Notifier; + +class Observer +{ + public: + virtual void ObserveString(int32 what, BString str) {}; + virtual void ObserveInteger(int32 what, int32 value) {}; + virtual void ObservePointer(int32 what, void* ptr) {}; +}; +#endif diff --git a/application/ProtocolManager.cpp b/application/ProtocolManager.cpp new file mode 100644 index 0000000..04dc4e4 --- /dev/null +++ b/application/ProtocolManager.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include + +#include +#include + +#include + +#include "ProtocolManager.h" +#include "CayaProtocol.h" +#include "CayaUtils.h" + +static ProtocolManager* fInstance = NULL; + + +void +ProtocolManager::Init(BDirectory protocolDir) +{ + BEntry entry; + BPath path; + + protocolDir.Rewind(); + + while (protocolDir.GetNextEntry(&entry) == B_OK) { + path = BPath(&entry); + + image_id id = load_add_on(path.Path()); + if (id >= 0) { + CayaProtocol* (*main_protocol)(); + if (get_image_symbol(id, "main_protocol", B_SYMBOL_TYPE_TEXT, + (void**)&main_protocol) == B_OK) { + CayaProtocol* cayp = (*main_protocol)(); + + if (cayp) { + printf("Found a new Protocol: %s [%s]\n", cayp->GetFriendlySignature(), + cayp->GetSignature()); + fProtocolMap.AddItem(BString(cayp->GetSignature()), cayp); + fAddonMap.AddItem(BString(cayp->GetSignature()), new BPath(path)); + } else + unload_add_on(id); + } else + unload_add_on(id); + } + } +} + + +ProtocolManager::ProtocolManager() +{ +} + + +ProtocolManager* +ProtocolManager::Get() +{ + if (fInstance == NULL) + fInstance = new ProtocolManager(); + return fInstance; +} + + +CayaProtocol* +ProtocolManager::GetProtocol(BString signature) +{ + return fProtocolMap.ValueFor(signature); +} + + +BList* +ProtocolManager::GetProtocols() +{ + return fProtocolMap.Items(); +} + + +BPath* +ProtocolManager::GetProtocolPath(BString signature) +{ + return fAddonMap.ValueFor(signature); +} + + +BBitmap* +ProtocolManager::GetProtocolIcon(BString signature) +{ + BPath* path = fAddonMap.ValueFor(signature); + return ReadNodeIcon(path->Path(), B_LARGE_ICON, true); +} diff --git a/application/ProtocolManager.h b/application/ProtocolManager.h new file mode 100644 index 0000000..1a00016 --- /dev/null +++ b/application/ProtocolManager.h @@ -0,0 +1,37 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ProtocolManager_h +#define ProtocolManager_h + +#include +#include +#include + +#include "KeyMap.h" +#include "CayaProtocol.h" + +class BBitmap; + +class ProtocolManager +{ +public: + void Init(BDirectory protocolDir); + static ProtocolManager* Get(); + + CayaProtocol* GetProtocol(BString signature); + + BList* GetProtocols(); + + BPath* GetProtocolPath(BString signature); + BBitmap* GetProtocolIcon(BString signature); + + private: + + ProtocolManager(); + + KeyMap fProtocolMap; + KeyMap fAddonMap; +}; +#endif diff --git a/application/ProtocolSettings.cpp b/application/ProtocolSettings.cpp new file mode 100644 index 0000000..1a7c79f --- /dev/null +++ b/application/ProtocolSettings.cpp @@ -0,0 +1,435 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Copyright 2003-2009, IM Kit Team. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Davidson, slaad@bong.com.au + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "CayaProtocol.h" +#include "CayaResources.h" +#include "ProtocolManager.h" +#include "ProtocolSettings.h" + +#define _T(str) (str) + +const float kDividerWidth = 1.0f; + + +ProtocolSettings::ProtocolSettings(CayaProtocol* cayap) + : fProtocol(cayap), + fTemplate(new BMessage()), + fSettings(new BMessage()) +{ + _Init(); +} + + +ProtocolSettings::~ProtocolSettings() +{ + delete fTemplate; + delete fSettings; +} + + +status_t +ProtocolSettings::InitCheck() const +{ + return fStatus; +} + + +BList* +ProtocolSettings::Accounts() const +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return NULL; + + path.Append("Caya/Protocols"); + path.Append(fProtocol->GetSignature()); + if (create_directory(path.Path(), 0755) != B_OK) + return NULL; + + BList* list = new BList(); + BDirectory dir(path.Path()); + BEntry entry; + while (dir.GetNextEntry(&entry) == B_OK) { + BFile file(&entry, B_READ_ONLY); + BMessage msg; + + if (msg.Unflatten(&file) == B_OK) { + char buffer[B_PATH_NAME_LENGTH]; + if (entry.GetName(buffer) == B_OK) { + BString* string = new BString(buffer); + list->AddItem(string); + } + } + } + + return list; +} + + +status_t +ProtocolSettings::Load(const char* account) +{ + status_t ret = B_ERROR; + + // Find user's settings path + BPath path; + if ((ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK) + return ret; + + // Create path + path.Append("Caya/Protocols"); + path.Append(fProtocol->GetSignature()); + if ((ret = create_directory(path.Path(), 0755)) != B_OK) + return ret; + + // Load settings file + path.Append(account); + BFile file(path.Path(), B_READ_ONLY); + return fSettings->Unflatten(&file); +} + + +status_t +ProtocolSettings::Save(const char* account) +{ + status_t ret = B_ERROR; + + // Find user's settings path + BPath path; + if ((ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK) + return ret; + + // Create path + path.Append("Caya/Protocols"); + path.Append(fProtocol->GetSignature()); + if ((ret = create_directory(path.Path(), 0755)) != B_OK) + return ret; + + // Load settings file + path.Append(account); + BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); + return fSettings->Flatten(&file); +} + + +status_t +ProtocolSettings::Delete(const char* account) +{ + status_t ret = B_ERROR; + + // Find user's settings path + BPath path; + if ((ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK) + return ret; + + // Create path + path.Append("Caya/Protocols"); + path.Append(fProtocol->GetSignature()); + if ((ret = create_directory(path.Path(), 0755)) != B_OK) + return ret; + path.Append(account); + + // Delete settings file + BEntry entry(path.Path()); + if ((ret = entry.Remove()) != B_OK) + return ret; + + delete fSettings; + fSettings = new BMessage(); + return B_OK; +} + + +void +ProtocolSettings::BuildGUI(BView* parent) +{ + if (!parent) + debugger("Couldn't build protocol's settings GUI on a NULL parent!"); + + BMessage curr; + float inset = ceilf(be_plain_font->Size() * 0.7f); + + // Setup layout + parent->SetLayout(new BGroupLayout(B_VERTICAL)); + BGroupLayoutBuilder layout(B_VERTICAL, inset); + + for (int32 i = 0; fTemplate->FindMessage("setting", i, &curr) == B_OK; i++) { + char temp[512]; + + // Get stuff from settings template + const char* name = curr.FindString("name"); + const char* desc = curr.FindString("description"); + const char* value = NULL; + int32 type = -1; + bool secret = false; + bool freeText = true; + bool multiLine = false; + BView* control = NULL; + BMenu* menu = NULL; + + // Ignore settings with errors + if (curr.FindInt32("type", &type) != B_OK) + continue; + + switch (type) { + case B_STRING_TYPE: { + if (curr.FindString("valid_value")) { + // It's a "select one of these" setting + freeText = false; + + menu = new BPopUpMenu(name); + for (int j = 0; curr.FindString("valid_value", j); j++) { + BMenuItem* item + = new BMenuItem(curr.FindString("valid_value", j), NULL); + menu->AddItem(item); + } + + value = fSettings->FindString(name); + if (value) + menu->FindItem(value)->SetMarked(true); + } else { + // It's a free-text setting + if (curr.FindBool("multi_line", &multiLine) != B_OK) + multiLine = false; + + value = fSettings->FindString(name); + if (!value) + value = curr.FindString("default"); + + if (curr.FindBool("is_secret",&secret) != B_OK) + secret = false; + } + break; + } + case B_INT32_TYPE: { + if (curr.FindInt32("valid_value")) { + // It's a "select one of these" setting + freeText = false; + + menu = new BPopUpMenu(name); + + int32 def = 0; + status_t hasValue = fSettings->FindInt32(name, 0, &def); + + if (hasValue != B_OK) + hasValue = curr.FindInt32("default", 0, &def); + + int32 v = 0; + for (int32 j = 0; curr.FindInt32("valid_value", j, &v) == B_OK; j++) { + sprintf(temp, "%ld", v); + + BMenuItem* item = new BMenuItem(temp, NULL); + + if (hasValue != B_OK && j == 0) + item->SetMarked(true); + else if ((hasValue == B_OK) && (def == v)) + item->SetMarked(true); + + menu->AddItem(item); + } + } else { + // It's a free-text (but number) setting + int32 v = 0; + + if (fSettings->FindInt32(name, &v) == B_OK) { + sprintf(temp,"%ld", v); + value = temp; + } else if (curr.FindInt32("default", &v) == B_OK) { + sprintf(temp,"%ld", v); + value = temp; + } + + if (curr.FindBool("is_secret",&secret) != B_OK) + secret = false; + } + break; + } + case B_BOOL_TYPE: { + bool active; + + if (fSettings->FindBool(name, &active) != B_OK) { + if (curr.FindBool("default", &active) != B_OK) + active = false; + } + + control = new BCheckBox(name, _T(desc), NULL); + if (active) + dynamic_cast(control)->SetValue(B_CONTROL_ON); + break; + } + default: + continue; + } + + if (!value) + value = ""; + + if (!control) { + if (freeText) { + if (!multiLine) { + control = new BTextControl(name, _T(desc), value, NULL); + if (secret) { + dynamic_cast(control)->TextView()->HideTyping(true); + dynamic_cast(control)->SetText(_T(value)); + } + dynamic_cast(control)->SetDivider(kDividerWidth); + } else { + BStringView* label = new BStringView("NA", _T(desc), B_WILL_DRAW); + layout.Add(label); + + NotifyingTextView* textView + = new NotifyingTextView(name); + control = new BScrollView("NA", textView, 0, false, true); + textView->SetText(_T(value)); + } + } else { + control = new BMenuField(name, _T(desc), menu); + dynamic_cast(control)->SetDivider(kDividerWidth); + } + } + +#if 0 + if (curr.FindString("help")) + gHelper.SetHelp(control, strdup(curr.FindString("help"))); +#endif + + layout.Add(control); + } + + layout.AddGlue(); + parent->AddChild(layout); +} + + +status_t +ProtocolSettings::SaveGUI(BView* parent) +{ + if (!parent) + debugger("Couldn't save protocol's settings GUI on a NULL parent!"); + + BMessage cur; + for (int32 i = 0; fTemplate->FindMessage("setting", i, &cur) == B_OK; i++) { + const char* name = cur.FindString("name"); + + // Skip NULL names + if (!name) + continue; + + int32 type = -1; + if (cur.FindInt32("type", &type) != B_OK) + continue; + + BView* view = parent->FindView(name); + if (!view) + continue; + + BTextControl* textControl + = dynamic_cast(view); + if (textControl) { + switch (type) { + case B_STRING_TYPE: + fSettings->AddString(name, textControl->Text()); + break; + case B_INT32_TYPE: + fSettings->AddInt32(name, atoi(textControl->Text())); + break; + default: + return B_ERROR; + } + } + + BMenuField* menuField + = dynamic_cast(view); + if (menuField) { + BMenuItem* item = menuField->Menu()->FindMarked(); + if (!item) + return B_ERROR; + + switch (type) { + case B_STRING_TYPE: + fSettings->AddString(name, item->Label()); + break; + case B_INT32_TYPE: + fSettings->AddInt32(name, atoi(item->Label())); + break; + default: + return B_ERROR; + } + } + + BCheckBox* checkBox + = dynamic_cast(view); + if (checkBox) + fSettings->AddBool(name, (checkBox->Value() == B_CONTROL_ON)); + + NotifyingTextView* textView + = dynamic_cast(view); + if (textView) + fSettings->AddString(name, textView->Text()); + } + +fSettings->PrintToStream(); + return B_OK; +} + + +void +ProtocolSettings::_Init() +{ + // Find protocol add-on + BPath* dllPath = ProtocolManager::Get()->GetProtocolPath( + fProtocol->GetSignature()); + BFile file(dllPath->Path(), B_READ_ONLY); + if (file.InitCheck() < B_OK) { + fStatus = file.InitCheck(); + return; + } + + BResources resources(&file); + if (resources.InitCheck() != B_OK) { + fStatus = resources.InitCheck(); + return; + } + + size_t size; + const void* data = resources.LoadResource(B_MESSAGE_TYPE, + kProtocolSettingsTemplate, &size); + if (!data) { + fStatus = B_BAD_VALUE; + return; + } + + // Load protocol's settings template + fTemplate->Unflatten((const char*)data); +} diff --git a/application/ProtocolSettings.h b/application/ProtocolSettings.h new file mode 100644 index 0000000..28d7426 --- /dev/null +++ b/application/ProtocolSettings.h @@ -0,0 +1,38 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Copyright 2003-2009, IM Kit Team. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PROTOCOL_SETTINGS_H +#define _PROTOCOL_SETTINGS_H + +class BMessage; +class CayaProtocol; + +class ProtocolSettings { +public: + ProtocolSettings(CayaProtocol* cayap); + ~ProtocolSettings(); + + status_t InitCheck() const; + + BList* Accounts() const; + + status_t Load(const char* account); + status_t Save(const char* account); + status_t Delete(const char* account); + + void BuildGUI(BView* parent); + status_t SaveGUI(BView* parent); + +private: + status_t fStatus; + CayaProtocol* fProtocol; + BString fAccount; + BMessage* fTemplate; + BMessage* fSettings; + + void _Init(); +}; + +#endif // _PROTOCOL_SETTINGS_H diff --git a/application/Server.cpp b/application/Server.cpp new file mode 100644 index 0000000..9175d9a --- /dev/null +++ b/application/Server.cpp @@ -0,0 +1,254 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include +#include + +#include "AccountManager.h" +#include "ImageCache.h" +#include "LooperCayaProtocol.h" +#include "ProtocolManager.h" +#include "Server.h" +#include "MainWindow.h" +#include "RosterItem.h" +#include "ChatWindow.h" +#include +#include "Account.h" + +Server::Server(MainWindow* mainWindow) + : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) +{ + CayaProtocol* pp = ProtocolManager::Get()->GetProtocol("gtalk"); + if (!pp) + debugger("something wrong"); + + //FIXME: here just a first draft of the final design: + + Account* gtalkAccount = new Account(mainWindow); + + pp->Init(gtalkAccount); + + fMainWindow = mainWindow; + fProtocol = new LooperCayaProtocol(pp); +} + + +void +Server::Quit() +{ + ContactLinker* linker = NULL; + while ((linker = fRosterMap.ValueAt(0))) { + linker->DeleteWindow(); + linker->DeletePopUp(); + fRosterMap.RemoveItemAt(0); + } +} + + +void +Server::Login() +{ + BMessage* msg = new BMessage(IM_MESSAGE); + msg->AddInt32("im_what", IM_SET_STATUS); + msg->AddInt32("status", CAYA_ONLINE); + fProtocol->PostMessage(msg); +} + + +void +Server::SendProtocolMessage(BMessage* msg) +{ + if (msg != NULL) + fProtocol->PostMessage(msg); +} + + +void +Server::UpdateSettings(BMessage settings) +{ + fProtocol->Protocol()->UpdateSettings(settings); +} + + +filter_result +Server::Filter(BMessage* message, BHandler **target) +{ + filter_result result = B_DISPATCH_MESSAGE; + + switch(message->what) { + case IM_SERVER_BASED_CONTACT_LIST: + { + int i = 0; + BString id; + while (message->FindString("id", i++, &id) == B_OK) { + bool found = false; + ContactLinker* item = fRosterMap.ValueFor(id, &found); + + if (!found) { + item = new ContactLinker(id.String(), Looper()); + fRosterMap.AddItem(id, item); + } + } + result = B_SKIP_MESSAGE; + break; + } + case OPEN_WINDOW: + { + int index = message->FindInt32("index"); + RosterItem* ritem = fMainWindow->ItemAt(index); + if (ritem != NULL) + ritem->GetContactLinker()->ShowWindow(); + result = B_SKIP_MESSAGE; + break; + } + case CLOSE_WINDOW: + { + BString id = message->FindString("id"); + if (id != "") { + bool found = false; + ContactLinker *item = fRosterMap.ValueFor(id, &found); + + if (found) + item->HideWindow(); + } + result = B_SKIP_MESSAGE; + break; + } + case IM_MESSAGE: + result = ImMessage(message); + break; + } + + return result; +} + + +RosterMap +Server::RosterItems() const +{ + return fRosterMap; +} + + +RosterItem* +Server::RosterItemForId(BString id) +{ + bool found = false; + ContactLinker* item = fRosterMap.ValueFor(id, &found); + return item ? item->GetRosterItem() : NULL; +} + + +filter_result +Server::ImMessage(BMessage* msg) +{ + filter_result result = B_DISPATCH_MESSAGE; + int32 im_what = msg->FindInt32("im_what"); + + switch (im_what) { + case IM_STATUS_SET: + { + int32 status; + const char* protocol; + + if (msg->FindInt32("status", &status) != B_OK) + return B_SKIP_MESSAGE; + if (msg->FindString("protocol", &protocol) != B_OK) + return B_SKIP_MESSAGE; + + AccountManager* accountManager = AccountManager::Get(); + accountManager->SetStatus((CayaStatus)status); + break; + } + case IM_STATUS_CHANGED: + { + int32 status; + + if (msg->FindInt32("status", &status) != B_OK) + return B_SKIP_MESSAGE; + + ContactLinker* linker = EnsureContactLinker(msg->FindString("id")); + linker->SetNotifyStatus((CayaStatus)status); + linker->SetNotifyPersonalStatus(msg->FindString("message")); + break; + } + case IM_CONTACT_INFO: + { + ContactLinker* linker = EnsureContactLinker(msg->FindString("id")); + BString fullName = msg->FindString("nick"); + if (fullName != "") + linker->SetNotifyName(fullName); + break; + } + case IM_AVATAR_CHANGED: + { + ContactLinker* linker = EnsureContactLinker(msg->FindString("id")); + entry_ref ref; + if (linker) { + if (msg->FindRef("ref", &ref) == B_OK) { + //BPath fullPath(&ref); + //BBitmap *bitmap = ImageCache::GetImage(BString(fullPath.Path()), BString(fullPath.Path())); + BBitmap *bitmap = BTranslationUtils::GetBitmap(&ref); + linker->SetNotifyAvatarBitmap(bitmap); + } else + linker->SetNotifyAvatarBitmap(NULL); + } + break; + } + case IM_SEND_MESSAGE: + fProtocol->PostMessage(msg); + break; + case IM_MESSAGE_RECEIVED: + { + BString id = msg->FindString("id"); + if (id != "") { + bool found = false; + ContactLinker* item = fRosterMap.ValueFor(id, &found); + if (found) { + ChatWindow* win = item->GetChatWindow(); + item->ShowWindow(); + win->PostMessage(msg); + } + } + result = B_SKIP_MESSAGE; + break; + } + default: + msg->PrintToStream(); + break; + } + + return result; +} + + +ContactLinker* +Server::EnsureContactLinker(BString id) +{ + ContactLinker* item = NULL; + if (id != "") { + bool found = false; + item = fRosterMap.ValueFor(id, &found); + + if (!found) { + item = new ContactLinker(id.String(), Looper()); + fRosterMap.AddItem(id, item); + } + } + + return item; +} + +ContactLinker* +Server::GetOwnContact() +{ + return fMySelf; +} diff --git a/application/Server.h b/application/Server.h new file mode 100644 index 0000000..ca96919 --- /dev/null +++ b/application/Server.h @@ -0,0 +1,52 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SERVER_H +#define _SERVER_H + +#include +#include + +#include "CayaConstants.h" +#include "ContactLinker.h" +#include "KeyMap.h" + +class MainWindow; +class RosterItem; +class LooperCayaProtocol; + +typedef KeyMap RosterMap; + +class Server: public BMessageFilter { +public: + Server(MainWindow* mainWindow); + + virtual filter_result Filter(BMessage* message, BHandler** target); + filter_result ImMessage(BMessage* msg); + + void UpdateSettings(BMessage settings); + + void Login(); + + void SendProtocolMessage(BMessage* msg); + void SendChatMessage(BMessage* msg); + + RosterMap RosterItems() const; + RosterItem* RosterItemForId(BString id); + + void Quit(); + + //TODO: there should be a contact for each account. + ContactLinker* GetOwnContact(); + +private: + ContactLinker* EnsureContactLinker(BString id); + + RosterMap fRosterMap; + MainWindow* fMainWindow; + LooperCayaProtocol* fProtocol; + ContactLinker* fMySelf; +}; + +#endif // _SERVER_H diff --git a/application/TheApp.cpp b/application/TheApp.cpp new file mode 100644 index 0000000..bcdc216 --- /dev/null +++ b/application/TheApp.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include +#include +#include + +#include "Caya.h" +#include "TheApp.h" +#include "FilePanel.h" +#include "MainWindow.h" +#include "Emoticor.h" +#include "ProtocolManager.h" + + +TheApp::TheApp() + : BApplication(CAYA_SIGNATURE), + fMainWin(NULL) +{ +} + + +void +TheApp::ReadyToRun() +{ + app_info theInfo; + + if (be_app->GetAppInfo(&theInfo) == B_OK) { + BPath applicationDirectory(&theInfo.ref); + applicationDirectory.GetParent(&applicationDirectory); + + BPath currentPath = applicationDirectory; + currentPath.Append("smileys"); + currentPath.Append("settings.xml"); + BEntry entry(currentPath.Path()); + if (entry.Exists()) + Emoticor::Get()->LoadConfig(currentPath.Path()); + else { + BString msg("Can't find smileys settings in:\n\n"); + msg << currentPath.Path(); + BAlert* alert = new BAlert("", msg.String(), "Ouch!"); + alert->Go(); + } + printf("Loaded Emoticons settings from: %s\n", currentPath.Path()); + + currentPath = applicationDirectory; + currentPath.Append("protocols"); + if (BEntry(currentPath.Path()).Exists()) { + printf("Looking for protocols from: %s\n", currentPath.Path()); + ProtocolManager::Get()->Init(BDirectory(currentPath.Path())); + } else { + BString msg("Can't find protocols in:\n\n"); + msg << currentPath.Path(); + BAlert* alert = new BAlert("", msg.String(), "Ouch!"); + alert->Go(); + PostMessage(B_QUIT_REQUESTED); + return; + } + } + + fMainWin = new MainWindow(); + fMainWin->Show(); +} + + +MainWindow* +TheApp::GetMainWindow() const +{ + return fMainWin; +} diff --git a/application/TheApp.h b/application/TheApp.h new file mode 100644 index 0000000..ecc6499 --- /dev/null +++ b/application/TheApp.h @@ -0,0 +1,25 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _THE_APP_H +#define _THE_APP_H + +#include + +#include "MainWindow.h" + +class TheApp : public BApplication { +public: + TheApp(); + + void ReadyToRun(); + + MainWindow* GetMainWindow() const; + +private: + MainWindow* fMainWin; + +}; + +#endif // _THE_APP_H diff --git a/application/WindowsManager.cpp b/application/WindowsManager.cpp new file mode 100644 index 0000000..68f2add --- /dev/null +++ b/application/WindowsManager.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#include "WindowsManager.h" + +WindowsManager* WindowsManager::fInstance = NULL; + +WindowsManager::WindowsManager() +{ + fCurrentPoint.Set(40.0f, 40.0f); +} + + +WindowsManager* +WindowsManager::Get() +{ + if (!fInstance) + fInstance = new WindowsManager(); + + return fInstance; +} + + +void +WindowsManager::RelocateWindow(BWindow* window) +{ + window->SetWorkspaces(B_CURRENT_WORKSPACE); + window->MoveTo(fCurrentPoint); + fCurrentPoint += BPoint(40.0f, 40.0f); +} diff --git a/application/WindowsManager.h b/application/WindowsManager.h new file mode 100644 index 0000000..3b5fd35 --- /dev/null +++ b/application/WindowsManager.h @@ -0,0 +1,25 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _WINDOWS_MANAGER_H_ +#define _WINDOWS_MANAGER_H_ + +#include +#include + +class WindowsManager +{ +public: + static WindowsManager* Get(); + + void RelocateWindow(BWindow* window); + +private: + WindowsManager(); + + static WindowsManager* fInstance; + BPoint fCurrentPoint; +}; + +#endif // _WINDOWS_MANAGER_H_ diff --git a/application/caya.rdef b/application/caya.rdef new file mode 100644 index 0000000..f27bbaf --- /dev/null +++ b/application/caya.rdef @@ -0,0 +1,95 @@ + +#include "Caya.h" +#include "CayaResources.h" + +resource app_signature CAYA_SIGNATURE; + +resource app_version { + major = 0, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "Caya", + long_info = "©2009-2010 Andrea Anzani, Pier Luigi Fiorini" +}; + +resource app_flags B_SINGLE_LAUNCH; + +resource file_types message; + +resource vector_icon { + $"6E636966080501040046020106023E40000000000000003D4000494000470000" + $"7EFFFFFFFFE5E1DA02000602000000BBC0004000000000009220244AF0000000" + $"33CCFC3366FF02000602000000BA000040000000000092202448800000336699" + $"FF6699CC02000602000000B9000040000000000092202448E00000CC0000FFFF" + $"000002000602000000BA000040000000000092202448800000FF9900FFFBFF00" + $"02000602000000BA000040000000000092202448800000006600FF00CC000A02" + $"06C22622C7562239222E342E2B2E3D4146364441483C50404C3C504A444A4E55" + $"44CBB634CBB83E5E2A0206C22622C7562239222E342E2B2E3D4146364441483C" + $"50404C3C504C464A505744CBB634CBB83E5E2A02024C265928532A583B59335D" + $"350610CAFFFEAF375335543B3B5A3B5A395D325D355D2C5D274F275627483241" + $"2C413541BDA7C2A83942BDA7C2A8394A3F463F463C40324036402A40234F2346" + $"2358325E2A5E395EBF5C5A3F5CBF5C5A3F544053080234313C310404FE372C37" + $"393739373A393B383B3A3B3B393B3A3B390406FE0B4536403640363F363E383E" + $"373E383E393E393E3A403B3F3B413B453A0405FE03453C453445344533433244" + $"324332403240323F323E343E333E3408024D2C4D3C0803553C4F3655300D0A00" + $"01001001178400040A020101000A010102000A0101032021210A010204053021" + $"2101178200040A0102070630212101178200040A010108301D2101178200040A" + $"0102090830212101178200040A030103000A040204051001178200040A050207" + $"061001178200040A060108301C2001178200040A07020908100117820004" +}; + +/* + * Status icons + */ + +// Online +resource(kOnlineIcon) #'VICN' array { + $"6E63696601020104040050B96455B9D6BEA917932FFF2766210102044030C345" + $"30BC3A30304030BC3A30C3454050BC3A50C34550504050C34550BC3A010A0001" + $"0002408000000000000000408000C60000C60000" +}; + +// Away +resource(kAwayIcon) #'VICN' array { + $"6E636966010201040400FFBA0055FFFFFFA9E8B732FFB891270102044030C345" + $"30BC3A30304030BC3A30C3454050BC3A50C34550504050C34550BC3A010A0001" + $"0002408000000000000000408000C60000C60000" +}; + +// Busy +resource(kBusyIcon) #'VICN' array { + $"6E636966010201040400E9060655E1CECEA9C43A3AFF752F2F0102044030C345" + $"30BC3A30304030BC3A30C3454050BC3A50C34550504050C34550BC3A010A0001" + $"0002408000000000000000408000C60000C60000" +}; + +// Offline +resource(kOfflineIcon) #'VICN' array { + $"6E63696601020104040000337F558B9097A92D3541FF0F12160102044030C345" + $"30BC3A30304030BC3A30C3454050BC3A50C34550504050C34550BC3A010A0001" + $"0002408000000000000000408000C60000C60000" +}; + +// Search icon +resource(kSearchIcon) #'VICN' array { + $"6E6369660805010200060338D2F73CD163BF82B23B84A94B88504870C900FFEF" + $"A5BDFFFCC0FFFFF890020106023E49240000000000003CAAAA4940004A3000FF" + $"FFFCC07CF1B706040192020016023A55A6BAC2293F0DA33E958646C2EB47A1D6" + $"0001FF9E020106023C00000000000000003C00004A30004A500000DCF4FFFF60" + $"94AA02001603360FF5B7B2B23AD6A4392A794ABC0B4AF035FF55C285005005FF" + $"0B0606AE0BB40BBF4D33C3AFB75DC173BDEFC607C13EC804CA28BD82C118B920" + $"C51BBB40BF07B8083AB6BC0605AE02B57D3EB9B9C3EFB7BB44BBB751BD75C936" + $"CA8EC1B1402F0A093B593D5BBFCDC93E455BC516C5F160465B435D4544510A04" + $"5A425E3F5A3D574008022D40BE1B3108023042BF00BAD108023344BFB3BC1D08" + $"023646C072BD750802264329440204423AC2BF3ABE583A384438BF2438C38B42" + $"4EBE584EC2BF4E4C444CC38B4CBF240606BA0A4C51565B585AC91CCA4EC983C9" + $"E959584F4E4B4D050A00010A12414992000000000000414992CA3294CA674701" + $"178400040A06010A02414992000000000000414992CA3294CA67470A00010912" + $"414992000000000000414992CA3294CA674701178400040A0501090241499200" + $"0000000000414992CA3294CA67470A070109023D49920000000000003D49923A" + $"DA753AC02E" +}; diff --git a/application/preferences/AccountListItem.cpp b/application/preferences/AccountListItem.cpp new file mode 100644 index 0000000..7b3641f --- /dev/null +++ b/application/preferences/AccountListItem.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include "AccountListItem.h" +#include "CayaProtocol.h" +#include "ProtocolSettings.h" + + +AccountListItem::AccountListItem(CayaProtocol* cayap, const char* account) + : BStringItem(account), + fProtocol(cayap), + fAccount(account), + fBaselineOffset(0) +{ + fSettings = new ProtocolSettings(cayap); + fSettings->Load(account); +} + + +AccountListItem::~AccountListItem() +{ + delete fSettings; +} + + +ProtocolSettings* +AccountListItem::Settings() const +{ + return fSettings; +} + + +CayaProtocol* +AccountListItem::Protocol() const +{ + return fProtocol; +} + + +const char* +AccountListItem::Account() const +{ + return fAccount.String(); +} + + +void +AccountListItem::DrawItem(BView* owner, BRect frame, bool complete) +{ + rgb_color highColor = owner->HighColor(); + rgb_color lowColor = owner->LowColor(); + + // Draw selection + if (IsSelected()) { + rgb_color highlightColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR); + + owner->SetLowColor(highlightColor); + owner->SetHighColor(highlightColor); + owner->FillRect(frame); + } + + // Draw account name + rgb_color textColor = ui_color(B_CONTROL_TEXT_COLOR); + owner->MovePenTo(frame.left, frame.top + fBaselineOffset); + if (!IsEnabled()) + owner->SetHighColor(tint_color(textColor, B_LIGHTEN_2_TINT)); + else + owner->SetHighColor(textColor); + owner->DrawString(Text()); + + owner->SetHighColor(highColor); + owner->SetLowColor(lowColor); +} + + +void +AccountListItem::Update(BView* owner, const BFont* font) +{ + if (Text()) + SetWidth(font->StringWidth(Text())); + + font_height height; + font->GetHeight(&height); + + fBaselineOffset = 2 + ceilf(height.ascent + height.leading / 2); + + SetHeight(ceilf(height.ascent) + ceilf(height.descent) + + ceilf(height.leading) + 4); +} diff --git a/application/preferences/AccountListItem.h b/application/preferences/AccountListItem.h new file mode 100644 index 0000000..b02af58 --- /dev/null +++ b/application/preferences/AccountListItem.h @@ -0,0 +1,36 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ACCOUNT_LIST_ITEM_H +#define _ACCOUNT_LIST_ITEM_H + +#include +#include + +class CayaProtocol; +class ProtocolSettings; + +class AccountListItem : public BStringItem { +public: + AccountListItem(CayaProtocol* cayap, + const char* account); + virtual ~AccountListItem(); + + ProtocolSettings* Settings() const; + CayaProtocol* Protocol() const; + const char* Account() const; + + void DrawItem(BView* owner, BRect frame, + bool complete = false); + + void Update(BView* owner, const BFont* font); + +private: + CayaProtocol* fProtocol; + BString fAccount; + ProtocolSettings* fSettings; + float fBaselineOffset; +}; + +#endif // _ACCOUNT_LIST_ITEM_H diff --git a/application/preferences/PreferencesAccounts.cpp b/application/preferences/PreferencesAccounts.cpp new file mode 100644 index 0000000..5312bef --- /dev/null +++ b/application/preferences/PreferencesAccounts.cpp @@ -0,0 +1,300 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "AccountListItem.h" +#include "CayaProtocol.h" +#include "PreferencesAccounts.h" +#include "ProtocolManager.h" +#include "ProtocolSettings.h" + +const uint32 kAddAccount = 'ADAC'; +const uint32 kEditAccount = 'EDAC'; +const uint32 kDelAccount = 'DLAC'; +const uint32 kSelect = 'SELT'; + +const uint32 kCancel = 'CANC'; +const uint32 kOK = 'SAVE'; +const uint32 kChanged = 'CHGD'; + + +class AccountView : public BView { +public: + AccountView(const char* name) + : BView(name, B_WILL_DRAW) + { + } + + void AttachedToWindow() + { + // Once we are attached to window, the GUI is already created + // so we can set our window as target for messages + for (int32 i = 0; i < CountChildren(); i++) { + BView* child = ChildAt(i); + + BMenu* menu = dynamic_cast(child); + BMenuField* menuField + = dynamic_cast(child); + BTextControl* textControl + = dynamic_cast(child); + NotifyingTextView* textView + = dynamic_cast(child); + BCheckBox* checkBox = dynamic_cast(child); + + if (menuField) + menu = menuField->Menu(); + + if (menu) { + for (int32 j = 0; j < menu->CountItems(); j++) { + BMenuItem* item = menu->ItemAt(j); + item->SetMessage(new BMessage(kChanged)); + item->SetTarget(Window()); + } + + menu->SetTargetForItems(Window()); + } + + if (textControl) { + textControl->SetMessage(new BMessage(kChanged)); + textControl->SetTarget(Window()); + } + + if (checkBox) { + checkBox->SetMessage(new BMessage(kChanged)); + checkBox->SetTarget(Window()); + } + + if (textView) { + textView->SetMessage(new BMessage(kChanged)); + textView->SetTarget(Window()); + } + } + } +}; + + +class AccountDialog : public BWindow { +public: + AccountDialog(const char* title, CayaProtocol* cayap, const char* account = NULL) + : BWindow(BRect(0, 0, 1, 1), title, B_MODAL_WINDOW, B_NOT_RESIZABLE | + B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE) + { + fSettings = new ProtocolSettings(cayap); + if (account) + fSettings->Load(account); + + fAccountName = new BTextControl("accountName", "Account name:", NULL, NULL); + fAccountName->SetFont(be_bold_font); + fAccountName->MakeFocus(); + if (account) { + fAccountName->SetText(account); + fAccountName->SetEnabled(false); + } + + Divider* divider = new Divider("divider", B_WILL_DRAW); + + fTop = new AccountView("top"); + fSettings->BuildGUI(fTop); + + BButton* cancel = new BButton("Cancel", new BMessage(kCancel)); + BButton* ok = new BButton("OK", new BMessage(kOK)); + + const float spacing = be_control_look->DefaultItemSpacing(); + + SetLayout(new BGroupLayout(B_VERTICAL, spacing)); + AddChild(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(fAccountName) + .Add(divider) + .Add(fTop) + .AddGroup(B_HORIZONTAL, spacing) + .AddGlue() + .Add(cancel) + .Add(ok) + .End() + .AddGlue() + .SetInsets(spacing, spacing, spacing, 0) + ); + + CenterOnScreen(); + } + + void MessageReceived(BMessage* msg) + { + switch (msg->what) { + case kOK: + if (fSettings->SaveGUI(fTop) == B_OK) + if (fSettings->Save(fAccountName->Text()) == B_OK) + Close(); +// TODO: Error! + break; + case kCancel: + Close(); + break; + case kChanged: + msg->PrintToStream(); + break; + default: + BWindow::MessageReceived(msg); + } + } + +private: + ProtocolSettings* fSettings; + AccountView* fTop; + BTextControl* fAccountName; +}; + + +PreferencesAccounts::PreferencesAccounts() + : BView("Accounts", B_WILL_DRAW) +{ + fListView = new BListView("accountsListView"); + fListView->SetInvocationMessage(new BMessage(kEditAccount)); + fListView->SetSelectionMessage(new BMessage(kSelect)); + + BScrollView* scrollView = new BScrollView("scrollView", fListView, + B_WILL_DRAW, false, true); + + BList* protocols = ProtocolManager::Get()->GetProtocols(); + + fProtosMenu = new BMenu("Add"); + for (int32 i = 0; i < protocols->CountItems(); i++) { + CayaProtocol* cayap + = reinterpret_cast(protocols->ItemAtFast(i)); + ProtocolSettings* settings = new ProtocolSettings(cayap); + BList* accounts = settings->Accounts(); + + // Add accounts to list view + for (int32 j = 0; j < accounts->CountItems(); j++) { + BString* account = reinterpret_cast(accounts->ItemAtFast(j)); + AccountListItem* listItem = new AccountListItem(cayap, + account->String()); + fListView->AddItem(listItem); + } + + // Add menu items + BMessage* msg = new BMessage(kAddAccount); + msg->AddPointer("protocol", cayap); + + BitmapMenuItem* item = new BitmapMenuItem( + cayap->GetFriendlySignature(), msg, + ProtocolManager::Get()->GetProtocolIcon(cayap->GetSignature())); + fProtosMenu->AddItem(item); + + delete accounts; + delete settings; + } + + BMenuField* proto = new BMenuField("addAccountField", NULL, fProtosMenu); + fDelButton = new BButton(" - ", new BMessage(kDelAccount)); + fEditButton = new BButton("Edit...", new BMessage(kEditAccount)); + fDelButton->SetEnabled(false); + fEditButton->SetEnabled(false); + + const float spacing = be_control_look->DefaultItemSpacing(); + + SetLayout(new BGroupLayout(B_HORIZONTAL, spacing)); + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(scrollView) + .AddGroup(B_HORIZONTAL, spacing) + .Add(proto) + .Add(fDelButton) + .AddGlue() + .Add(fEditButton) + .End() + .SetInsets(spacing, spacing, spacing, spacing) + ); +} + + +void +PreferencesAccounts::AttachedToWindow() +{ + fListView->SetTarget(this); + fProtosMenu->SetTargetForItems(this); + fDelButton->SetTarget(this); + fEditButton->SetTarget(this); +} + + +void +PreferencesAccounts::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kSelect: { + int32 index; + + if (msg->FindInt32("index", &index) == B_OK) { + fDelButton->SetEnabled(index >= 0); + fEditButton->SetEnabled(index >= 0); + } + } + break; + case kAddAccount: { + void *protocol = NULL; + if (msg->FindPointer("protocol", &protocol) == B_OK) { + CayaProtocol* cayap = (CayaProtocol*) protocol; + + AccountDialog* dialog = new AccountDialog("Add account", cayap); + dialog->Show(); + } + break; + } + case kEditAccount: { + for (int32 i = 0; i < fListView->CountItems(); i++) { + int32 selected = fListView->CurrentSelection(i); + if (selected < 0) + continue; + + AccountListItem* item + = dynamic_cast(fListView->ItemAt(selected)); + + CayaProtocol* cayap = item->Protocol(); + const char* account = item->Account(); + + AccountDialog* dialog = new AccountDialog("Edit account", cayap, account); + dialog->Show(); + } + break; + } + case kDelAccount: { + for (int32 i = 0; i < fListView->CountItems(); i++) { + int32 selected = fListView->CurrentSelection(i); + if (selected < 0) + continue; + + AccountListItem* item + = dynamic_cast(fListView->ItemAt(selected)); + + const char* account = item->Account(); + ProtocolSettings* settings = item->Settings(); + if (settings->Delete(account) == B_OK) + fListView->RemoveItem(item); + delete settings; + } + break; + } + default: + BView::MessageReceived(msg); + } +} diff --git a/application/preferences/PreferencesAccounts.h b/application/preferences/PreferencesAccounts.h new file mode 100644 index 0000000..04f5a05 --- /dev/null +++ b/application/preferences/PreferencesAccounts.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PREFERENCES_ACCOUNTS_H +#define _PREFERENCES_ACCOUNTS_H + +#include + +class BListView; +class BMenu; +class BButton; + +class PreferencesAccounts : public BView { +public: + PreferencesAccounts(); + + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage* msg); + +private: + BListView* fListView; + BMenu* fProtosMenu; + BButton* fDelButton; + BButton* fEditButton; +}; + +#endif // _PREFERENCES_ACCOUNTS_H diff --git a/application/preferences/PreferencesDialog.cpp b/application/preferences/PreferencesDialog.cpp new file mode 100644 index 0000000..933785a --- /dev/null +++ b/application/preferences/PreferencesDialog.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include +#include +#include + +#include "PreferencesDialog.h" +#include "PreferencesAccounts.h" + +const int32 kOK = 'SAVE'; + + +PreferencesDialog::PreferencesDialog() + : BWindow(BRect(0, 0, 400, 400), "Preferences", B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_CLOSE_ON_ESCAPE) +{ + BTabView* tabView = new BTabView("tabView", B_WIDTH_AS_USUAL); + tabView->AddTab(new PreferencesAccounts()); + + BButton* ok = new BButton("OK", new BMessage(kOK)); + + const float spacing = be_control_look->DefaultItemSpacing(); + + SetLayout(new BGroupLayout(B_VERTICAL, + be_control_look->DefaultItemSpacing())); + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(tabView) + .AddGroup(B_HORIZONTAL) + .AddGlue() + .Add(ok) + .SetInsets(spacing, spacing, 0, 0) + .End() + .SetInsets(spacing, spacing, spacing, spacing) + ); + + CenterOnScreen(); +} + + +void +PreferencesDialog::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kOK: + Close(); + break; + default: + BWindow::MessageReceived(msg); + } +} diff --git a/application/preferences/PreferencesDialog.h b/application/preferences/PreferencesDialog.h new file mode 100644 index 0000000..641290f --- /dev/null +++ b/application/preferences/PreferencesDialog.h @@ -0,0 +1,17 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PREFERENCES_DIALOG_H +#define _PREFERENCES_DIALOG_H + +#include + +class PreferencesDialog : public BWindow { +public: + PreferencesDialog(); + + virtual void MessageReceived(BMessage* msg); +}; + +#endif // _PREFERENCES_DIALOG_H diff --git a/application/views/CayaRenderView.cpp b/application/views/CayaRenderView.cpp new file mode 100644 index 0000000..e628d65 --- /dev/null +++ b/application/views/CayaRenderView.cpp @@ -0,0 +1,93 @@ +#include "CayaRenderView.h" +#include "Theme.h" +#include "RunView.h" + +CayaRenderView::CayaRenderView(const char *name, const char* smileyConfig) : + RunView( BRect(0, 0, 1, 1), name, fTheme = new Theme(name, COL_MAX_COLORS + 1, COL_MAX_COLORS + 1, MAX_RENDERS + 1), B_FOLLOW_ALL, B_WILL_DRAW ) +{ + if (smileyConfig) + Emoticor::Get()->LoadConfig(smileyConfig); + + PrepareTheme(fTheme); + + SetViewColor(245, 245, 245, 0); + SetLowColor(245, 245, 245, 0); + SetHighColor(0, 0, 0, 0); + + + SetTimeStampFormat(NULL); + if ( IsHidden() ) + Show(); + ScrollToBottom(); +} + +void +CayaRenderView::AppendOtherMessage(const char* message) +{ + Append(fOtherNick.String(), COL_OTHERNICK, COL_OTHERNICK, R_TEXT); + Append(": ", COL_OTHERNICK, COL_OTHERNICK, R_TEXT); + AddEmoticText(message, COL_TEXT, R_TEXT, COL_TEXT,R_EMOTICON); + Append("\n", COL_TEXT, COL_TEXT, R_TEXT); + ScrollToSelection(); +} + +void +CayaRenderView::AppendOwnMessage(const char* message) +{ + Append("You say: ", COL_OWNNICK, COL_OWNNICK, R_TEXT); + AddEmoticText(message, COL_TEXT, R_TEXT,COL_TEXT,R_EMOTICON); + Append("\n", COL_TEXT, COL_TEXT, R_TEXT); + ScrollToSelection(); +} + + +void +CayaRenderView::AddEmoticText(const char * txt, int16 cols , int16 font , int16 cols2 , int16 font2) +{ + Emoticor::Get()->AddText(this, txt, cols, font, cols2, font2); +} + +void +CayaRenderView::PrepareTheme(Theme *fTheme) +{ + Theme::TimestampFore = COL_TIMESTAMP_DUMMY; + Theme::TimestampBack = COL_TIMESTAMP_DUMMY; + Theme::TimespaceFore = COL_MAX_COLORS; + Theme::TimespaceBack = COL_MAX_COLORS; + Theme::TimespaceFont = MAX_RENDERS; + Theme::TimestampFont = R_TIMESTAMP_DUMMY; + Theme::NormalFore = COL_TEXT; + Theme::NormalBack = COL_TEXT; + Theme::NormalFont = R_TEXT; + Theme::SelectionBack = COL_SELECTION; + + fTheme->WriteLock(); + fTheme->SetForeground(COL_URL, 5, 5, 150); + fTheme->SetBackground(COL_URL, 255, 255, 255); + + fTheme->SetForeground(COL_TIMESTAMP, 130, 130, 130); + fTheme->SetBackground(COL_TIMESTAMP, 255, 255, 255); + + fTheme->SetForeground(COL_TEXT, 0, 0, 0); + fTheme->SetBackground(COL_TEXT, 255, 255, 255); + + fTheme->SetForeground(COL_ACTION, 0, 0, 0); + fTheme->SetBackground(COL_ACTION, 255, 255, 255); + + fTheme->SetForeground(COL_SELECTION, 255, 255, 255); + fTheme->SetBackground(COL_SELECTION, 0, 0, 0); + + fTheme->SetForeground(COL_OWNNICK, 0, 0, 255); + fTheme->SetBackground(COL_OWNNICK, 255, 255, 255); + + fTheme->SetForeground(COL_OTHERNICK, 255, 0, 0); + fTheme->SetBackground(COL_OTHERNICK, 255, 255, 255); + + fTheme->SetTextRender(R_EMOTICON, &str); + + fTheme->SetSoftLineIndent(5.0); + fTheme->SetTextMargin(5.0); + + fTheme->WriteUnlock(); + +} diff --git a/application/views/CayaRenderView.h b/application/views/CayaRenderView.h new file mode 100644 index 0000000..5709b9f --- /dev/null +++ b/application/views/CayaRenderView.h @@ -0,0 +1,55 @@ +#ifndef _CayaRenderView_H +#define _CayaRenderView_H_ + +#include "RunView.h" +#include "SmileTextRender.h" + +class RunView; +class Theme; + +enum CayaRenderViewColors { + COL_URL = 0, + COL_TIMESTAMP, + COL_TEXT, + COL_OWNNICK, + COL_OTHERNICK, + COL_ACTION, + COL_SELECTION, + COL_TIMESTAMP_DUMMY, + COL_MAX_COLORS +}; + +enum { + R_URL = 0, + R_TEXT, + R_TIMESTAMP, + R_ACTION, + R_EMOTICON, + R_TIMESTAMP_DUMMY, + MAX_RENDERS +}; + +class CayaRenderView : public RunView +{ + public: + CayaRenderView(const char* name, const char* smileyConfig = NULL); + + void AppendOtherMessage(const char* message); + void AppendOwnMessage(const char* message); + void AddEmoticText(const char * txt, int16 cols , int16 font , int16 cols2 , int16 font2); + + void SetOwnNick(BString nick) { fOwnNick = nick; } + void SetOtherNick(BString nick) { fOtherNick = nick; } + + protected: + void PrepareTheme(Theme* theme); + + private: + BString fOwnNick; + BString fOtherNick; + Theme* fTheme; + SmileTextRender str; + +}; + +#endif diff --git a/application/views/ContactPopUp.cpp b/application/views/ContactPopUp.cpp new file mode 100644 index 0000000..c86964b --- /dev/null +++ b/application/views/ContactPopUp.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include +#include + +#include "BitmapView.h" +#include "ContactLinker.h" +#include "ContactPopUp.h" +#include "NotifyMessage.h" + +const window_feel kMenuWindowFeel = window_feel(1025); + +const int32 kNickChanged = 'NICH'; + + +ContactPopUp::ContactPopUp(ContactLinker* contact) + : BWindow(BRect(0, 0, 1, 1), "ContactPopUp", B_BORDERED_WINDOW_LOOK, + kMenuWindowFeel, B_NOT_MOVABLE | B_NOT_CLOSABLE | B_NOT_MINIMIZABLE | + B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS | + B_AVOID_FOCUS | B_AUTO_UPDATE_SIZE_LIMITS), + fCoords(B_ORIGIN) +{ + // Box to change nick name + fNickBox = new BTextControl("nickBox", NULL, contact->GetName(), + new BMessage(kNickChanged)); + + // Real nick name + fLabel = new BStringView("label", contact->GetId()); + + // Avatar bitmap + fAvatarView = new BitmapView("avatarView"); + fAvatarView->SetBitmap(contact->AvatarBitmap()); + + // Layout + SetLayout(new BGroupLayout(B_VERTICAL)); + AddChild(BGroupLayoutBuilder(B_HORIZONTAL, 10) + .AddGroup(B_VERTICAL) + .Add(fNickBox) + .Add(fLabel) + .AddGlue() + .End() + .Add(fAvatarView) + .SetInsets(10, 10, 10, 10) + ); +} + + +void +ContactPopUp::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kNickChanged: + break; + default: + BWindow::MessageReceived(msg); + } +} + + +void +ContactPopUp::MoveTo(BPoint where) +{ + if (fCoords != where) { + if (Lock()) { + BWindow::MoveTo(where); + fCoords = where; + Unlock(); + } + } +} + + +void +ContactPopUp::ObserveString(int32 what, BString str) +{ + switch (what) { + case STR_CONTACT_NAME: + if (Lock()) { + fLabel->SetText(str); + Unlock(); + } + break; + } +} + + +void +ContactPopUp::ObservePointer(int32 what, void* ptr) +{ + switch (what) { + case PTR_AVATAR_BITMAP: + if (Lock()) { + fAvatarView->SetBitmap((BBitmap*)ptr); + Unlock(); + } + break; + } +} + + +void +ContactPopUp::ObserveInteger(int32 what, int32 val) +{ + switch (what) { + case INT_CONTACT_STATUS: + break; + } +} diff --git a/application/views/ContactPopUp.h b/application/views/ContactPopUp.h new file mode 100644 index 0000000..5efae87 --- /dev/null +++ b/application/views/ContactPopUp.h @@ -0,0 +1,38 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CONTACT_POPUP_H +#define _CONTACT_POPUP_H + +#include + +#include "Observer.h" + +class BTextControl; +class BStringView; + +class BitmapView; +class ContactLinker; + +class ContactPopUp : public BWindow, public Observer { +public: + ContactPopUp(ContactLinker* contact); + + virtual void MessageReceived(BMessage* msg); + + void MoveTo(BPoint where); + +protected: + void ObserveString(int32 what, BString str); + void ObservePointer(int32 what, void* ptr); + void ObserveInteger(int32 what, int32 val); + +private: + BPoint fCoords; + BTextControl* fNickBox; + BStringView* fLabel; + BitmapView* fAvatarView; +}; + +#endif // _CONTACT_POPUP_H diff --git a/application/views/NicknameTextControl.cpp b/application/views/NicknameTextControl.cpp new file mode 100644 index 0000000..5f2706b --- /dev/null +++ b/application/views/NicknameTextControl.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include "NicknameTextControl.h" + + +NicknameTextControl::NicknameTextControl(const char* name, BMessage* message) + : BTextControl(name, NULL, NULL, message) +{ +} + + +void +NicknameTextControl::Draw(BRect updateRect) +{ + BRect rect(Bounds()); + + SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + FillRect(rect); +} diff --git a/application/views/NicknameTextControl.h b/application/views/NicknameTextControl.h new file mode 100644 index 0000000..70600cd --- /dev/null +++ b/application/views/NicknameTextControl.h @@ -0,0 +1,17 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _NICKNAME_TEXT_CONTROL_H +#define _NICKNAME_TEXT_CONTROL_H + +#include + +class NicknameTextControl : public BTextControl { +public: + NicknameTextControl(const char* name, BMessage* message); + + virtual void Draw(BRect updateRect); +}; + +#endif // _NICKNAME_TEXT_CONTROL_H diff --git a/application/views/RosterItem.cpp b/application/views/RosterItem.cpp new file mode 100644 index 0000000..8cd9fc1 --- /dev/null +++ b/application/views/RosterItem.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include + +#include "CayaUtils.h" +#include "ContactLinker.h" +#include "NotifyMessage.h" +#include "RosterItem.h" + + +RosterItem::RosterItem(const char* name, ContactLinker* contact) + : BStringItem(name), + fBitmap(NULL), + fStatus(CAYA_OFFLINE), + contactLinker(contact), + fVisible(true) +{ + rgb_color highlightColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR); + rgb_color darkenHighlightColor = tint_color(highlightColor, B_DARKEN_1_TINT); + + fGradient.AddColor(highlightColor, 0); + fGradient.AddColor(darkenHighlightColor, 255); +} + + +RosterItem::~RosterItem() +{ + delete fBitmap; +} + + +void +RosterItem::SetVisible(bool visible) +{ + fVisible = visible; +} + + +void +RosterItem::SetBitmap(BBitmap* bitmap) +{ + if (fBitmap != NULL) + delete fBitmap; + fBitmap = bitmap; +} + + +void +RosterItem::ObserveString(int32 what, BString str) +{ + switch (what) { + case STR_CONTACT_NAME: + SetText(str); + break; + case STR_PERSONAL_STATUS: + SetPersonalStatus(str); + break; + } +} + + +void +RosterItem::ObservePointer(int32 what, void* ptr) +{ + switch (what) { + case PTR_AVATAR_BITMAP: + SetBitmap((BBitmap*)ptr); + break; + } +} + + +void +RosterItem::ObserveInteger(int32 what, int32 val) +{ + switch (what) { + case INT_CONTACT_STATUS: + SetStatus((CayaStatus)val); + break; + } +} + + +void RosterItem::DrawItem(BView* owner, BRect frame, bool complete) +{ + if (Text() == NULL) + return; + + rgb_color highlightColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR); + rgb_color highColor = owner->HighColor(); + rgb_color lowColor = owner->LowColor(); + + // Draw selection + if (IsSelected()) { + fGradient.SetStart(frame.LeftTop()); + fGradient.SetEnd(frame.LeftBottom()); + owner->SetLowColor(highlightColor); + owner->FillRect(frame, fGradient); + } else if (complete) { + owner->SetHighColor(lowColor); + owner->FillRect(frame); + } + + // Draw contact status + switch (fStatus) { + case CAYA_ONLINE: + owner->SetHighColor(CAYA_GREEN_COLOR); + break; + case CAYA_EXTENDED_AWAY: + case CAYA_AWAY: + owner->SetHighColor(CAYA_ORANGE_COLOR); + break; + case CAYA_DO_NOT_DISTURB: + owner->SetHighColor(CAYA_RED_COLOR); + break; + case CAYA_OFFLINE: + break; + default: + break; + } + owner->FillEllipse(BRect(frame.left + 6, frame.top + 6, + frame.left + 6 + 7 , frame.top + 6 + 7)); + + // Draw contact name + owner->MovePenTo(frame.left + 20, frame.top + myfBaselineOffset); + owner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR)); + owner->DrawString(Text()); + + // Draw contact status string + owner->MovePenTo(frame.left + 20, frame.top + myfBaselineOffset + + myfBaselineOffset + 2); + owner->SetHighColor(tint_color(lowColor, B_DARKEN_1_TINT)); + if (fPersonalStatus.Length() == 0) + owner->DrawString(CayaStatusToString(fStatus)); + else + owner->DrawString(fPersonalStatus); + + // Draw separator between items + owner->StrokeLine(BPoint(frame.left, frame.bottom), BPoint(frame.right, frame.bottom)); + + // Draw avatar icon + if (fBitmap != NULL) { + float h = frame.Height() - 4; + BRect rect(frame.right - h - 2, frame.top + 2, frame.right - 2, frame.top + h ); + owner->SetDrawingMode(B_OP_ALPHA); + owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + owner->DrawBitmap(fBitmap, rect); + } + + owner->SetHighColor(highColor); + owner->SetLowColor(lowColor); +} + + +void +RosterItem::Update(BView* owner, const BFont* font) +{ + font_height fheight; + font->GetHeight(&fheight); + + myfBaselineOffset = 2 + ceilf(fheight.ascent + fheight.leading / 2); + + SetHeight((ceilf(fheight.ascent) + ceilf(fheight.descent) + + ceilf(fheight.leading) + 4 ) * 2); +} + + +void +RosterItem::SetStatus(CayaStatus status) +{ + if (fStatus != status) + fStatus = status; +} diff --git a/application/views/RosterItem.h b/application/views/RosterItem.h new file mode 100644 index 0000000..126165a --- /dev/null +++ b/application/views/RosterItem.h @@ -0,0 +1,57 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ROSTER_ITEM_H +#define _ROSTER_ITEM_H + +#include +#include +#include +#include +#include + +#include "CayaConstants.h" +#include "ContactLinker.h" +#include "Observer.h" + +class RosterItem : public BStringItem, public Observer { +public: + RosterItem(const char* name, ContactLinker* contact); + ~RosterItem(); + + bool IsVisible() const { return fVisible; } + void SetVisible(bool visible); + + void DrawItem(BView *owner, BRect frame, + bool complete = false); + + void Update(BView *owner, const BFont *font); + + ContactLinker* GetContactLinker() { return contactLinker;} + + CayaStatus Status() const { return fStatus; } + void SetStatus(CayaStatus status); + + BString PersonalStatus() const { return fPersonalStatus; } + void SetPersonalStatus(BString str) { fPersonalStatus = str; } + + BBitmap* Bitmap() const { return fBitmap; } + void SetBitmap(BBitmap *); + +protected: + void ObserveString(int32 what, BString str); + void ObservePointer(int32 what, void* ptr); + void ObserveInteger(int32 what, int32 val); + +private: + ContactLinker* contactLinker; + float myfBaselineOffset; + BString fPersonalStatus; + CayaStatus fStatus; + BBitmap* fBitmap; + bool fVisible; + BGradientLinear fGradient; +}; + +#endif // _ROSTER_ITEM_H diff --git a/application/views/RosterListView.cpp b/application/views/RosterListView.cpp new file mode 100644 index 0000000..42d7ae1 --- /dev/null +++ b/application/views/RosterListView.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include + +#include +#include +#include +#include + +#include "ContactLinker.h" +#include "RosterItem.h" +#include "RosterListView.h" + +const int32 kGetInfo = 'GINF'; +const int32 kShowLogs = 'SHLG'; +const int32 kAddPeople = 'ADPL'; + + +static int +compare_by_name(const void* _item1, const void* _item2) +{ + RosterItem* item1 = *(RosterItem**)_item1; + RosterItem* item2 = *(RosterItem**)_item2; + + return strcasecmp(item1->GetContactLinker()->GetName().String(), + item2->GetContactLinker()->GetName().String()); +} + + +static int +compare_by_status(const void* _item1, const void* _item2) +{ + RosterItem* item1 = *(RosterItem**)_item1; + RosterItem* item2 = *(RosterItem**)_item2; + + if (item1->Status() < item2->Status()) + return 1; + if (item1->Status() > item2->Status()) + return 2; + return 0; +} + + +RosterListView::RosterListView(const char* name) + : BListView(name, B_SINGLE_SELECTION_LIST, B_WILL_DRAW | B_FRAME_EVENTS | + B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE), + fPrevItem(NULL) +{ + // Context menu + fPopUp = new BPopUpMenu("contextMenu", false); + fPopUp->AddItem(new BMenuItem("Get Information", new BMessage(kGetInfo))); + fPopUp->AddItem(new BMenuItem("Show Logs", new BMessage(kShowLogs))); + fPopUp->AddItem(new BSeparatorItem()); + fPopUp->AddItem(new BMenuItem("Add to Address Book", + new BMessage(kAddPeople))); + fPopUp->SetTargetForItems(this); +} + + +// #pragama mark - + + +void +RosterListView::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kGetInfo: + msg->PrintToStream(); + break; + } +} + + +void +RosterListView::MouseMoved(BPoint where, uint32 code, const BMessage* msg) +{ + BListView::MouseMoved(where, code, msg); + return; + + switch (code) { + case B_INSIDE_VIEW: + { + // Mouse cursor is inside this view, hide last item's popup + // and show current item's popup + BListItem* item = ItemAt(IndexOf(where)); + RosterItem* ritem = reinterpret_cast(item); + + if (ritem == NULL) + return; + + // Hide previous item's popup + if ((fPrevItem != NULL) && (fPrevItem != ritem)) + fPrevItem->GetContactLinker()->HidePopUp(); + + // Show current item's popup + ritem->GetContactLinker()->ShowPopUp(ConvertToScreen(where)); + + // This will be the previous item + fPrevItem = ritem; + break; + } + case B_EXITED_VIEW: + // Mouse cursor leaved this view, hide last item's popup + if (fPrevItem != NULL) + fPrevItem->GetContactLinker()->HidePopUp(); + break; + } +} + + +void +RosterListView::MouseDown(BPoint where) +{ + BMessage* message = Looper()->CurrentMessage(); + + int32 buttons = 0; + (void)message->FindInt32("buttons", &buttons); + + if (buttons == B_SECONDARY_MOUSE_BUTTON) { + int32 index = IndexOf(where); + if (index >= 0) { + // Select list item + Select(index); + + // Show context menu if right button is clicked + (void)fPopUp->Go(ConvertToScreen(where), false, true, false); + } + } else + // Call original MouseDown() + BListView::MouseDown(where); +} + + +void +RosterListView::Draw(BRect updateRect) +{ + int32 count = CountItems(); + if (count == 0) + return; + + BRect itemFrame(0, 0, Bounds().right, -1); + for (int32 i = 0; i < count; i++) { + BListItem* item = ItemAt(i); + RosterItem* rosterItem = reinterpret_cast(item); + + if (!rosterItem->IsVisible()) + continue; + + itemFrame.bottom = itemFrame.top + ceilf(item->Height()) - 1; + + if (itemFrame.Intersects(updateRect)) + rosterItem->DrawItem(this, itemFrame); + + itemFrame.top = itemFrame.bottom + 1; + } +} + + +// #pragama mark - + + +void +RosterListView::Sort() +{ + SortItems(compare_by_name); +} diff --git a/application/views/RosterListView.h b/application/views/RosterListView.h new file mode 100644 index 0000000..7aea7b8 --- /dev/null +++ b/application/views/RosterListView.h @@ -0,0 +1,31 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ROSTER_LIST_VIEW_H +#define _ROSTER_LIST_VIEW_H + +#include + +class BPopUpMenu; + +class RosterItem; + +class RosterListView : public BListView +{ +public: + RosterListView(const char* name); + + virtual void MessageReceived(BMessage* msg); + virtual void MouseMoved(BPoint where, uint32 code, const BMessage*); + virtual void MouseDown(BPoint where); + virtual void Draw(BRect updateRect); + + void Sort(); + +private: + BPopUpMenu* fPopUp; + RosterItem* fPrevItem; +}; + +#endif // _ROSTER_LIST_VIEW_H diff --git a/application/views/StatusMenuItem.cpp b/application/views/StatusMenuItem.cpp new file mode 100644 index 0000000..75683fc --- /dev/null +++ b/application/views/StatusMenuItem.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include +#include + +#include + +#include "CayaResources.h" +#include "CayaUtils.h" +#include "StatusMenuItem.h" + +const float kSize = 16; +const float kCircle = 12; + + +StatusMenuItem::StatusMenuItem(const char* label, CayaStatus status, + bool custom, char shortcut, uint32 modifiers) + : BitmapMenuItem(label, NULL, NULL, shortcut, modifiers), + fStatus(status), + fCustom(custom) +{ + BMessage* msg = new BMessage(kSetStatus); + msg->AddInt32("status", fStatus); + msg->AddBool("custom", fCustom); + SetMessage(msg); + + SetIcon(); +} + + +CayaStatus +StatusMenuItem::Status() const +{ + return fStatus; +} + + +bool +StatusMenuItem::IsCustom() const +{ + return fCustom; +} + + +void +StatusMenuItem::SetIcon() +{ + image_info info; + if (our_image(info) != B_OK) + return; + + BFile file(info.name, B_READ_ONLY); + if (file.InitCheck() != B_OK) + return; + + BResources res(&file); + if (res.InitCheck() != B_OK) + return; + + int32 num = 0; + + switch (fStatus) { + case CAYA_ONLINE: + num = kOnlineIcon; + break; + case CAYA_EXTENDED_AWAY: + case CAYA_AWAY: + num = kAwayIcon; + break; + case CAYA_DO_NOT_DISTURB: + num = kBusyIcon; + break; + case CAYA_OFFLINE: + num = kOfflineIcon; + break; + default: + break; + } + + BBitmap* bitmap = IconFromResources(&res, num, B_MINI_ICON); + SetBitmap(bitmap); +} diff --git a/application/views/StatusMenuItem.h b/application/views/StatusMenuItem.h new file mode 100644 index 0000000..2e828eb --- /dev/null +++ b/application/views/StatusMenuItem.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _STATUS_MENU_ITEM_H +#define _STATUS_MENU_ITEM_H + +#include + +#include + +#include "CayaConstants.h" + +class BBitmap; + +const int32 kSetStatus = 'SEST'; + +class StatusMenuItem : public BitmapMenuItem { +public: + StatusMenuItem(const char* label, CayaStatus status, bool custom = false, + char shortcut = 0, uint32 modifiers = 0); + + CayaStatus Status() const; + bool IsCustom() const; + +private: + CayaStatus fStatus; + bool fCustom; + + void SetIcon(); +}; + +#endif // _STATUS_MENU_ITEM_H diff --git a/application/views/StatusView.cpp b/application/views/StatusView.cpp new file mode 100644 index 0000000..e3a8656 --- /dev/null +++ b/application/views/StatusView.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "AccountManager.h" +#include "BitmapView.h" +#include "CayaUtils.h" +#include "NicknameTextControl.h" +#include "StatusMenuItem.h" +#include "StatusView.h" + +const int32 kSetNickname = 'NICH'; + + +StatusView::StatusView(const char* name) + : BView(name, B_WILL_DRAW) +{ + // Nick name + fNickname = new NicknameTextControl("nickname", new BMessage(kSetNickname)); + + // Status menu + fStatusMenu = new BPopUpMenu("-"); + + // Add status menu items + int32 s = CAYA_ONLINE; + while (s >= CAYA_ONLINE && s < CAYA_STATUSES) { + StatusMenuItem* item = new StatusMenuItem(CayaStatusToString( + (CayaStatus)s), (CayaStatus)s); + fStatusMenu->AddItem(item); + + // Add items for custom messages + if (s == CAYA_ONLINE || s == CAYA_DO_NOT_DISTURB) { + item = new StatusMenuItem("Custom...", (CayaStatus)s, true); + fStatusMenu->AddItem(item); + fStatusMenu->AddItem(new BSeparatorItem()); + } + + // Mark offline status by default + if (s == CAYA_OFFLINE) + item->SetMarked(true); + + s++; + } + + // Menu field + BMenuField* statusField = new BMenuField("statusField", NULL, + fStatusMenu, NULL); + + // Icon + fAvatar = new BitmapView("icon"); + + // Set layout + SetLayout(new BGroupLayout(B_VERTICAL)); + AddChild(BGroupLayoutBuilder(B_HORIZONTAL, 5) + .AddGroup(B_VERTICAL) + .Add(fNickname) + .Add(statusField) + .AddGlue() + .End() + .Add(fAvatar) + ); +} + + +void +StatusView::AttachedToWindow() +{ + fNickname->SetTarget(this); + fStatusMenu->SetTargetForItems(this); +} + + +void +StatusView::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kSetNickname: + { + AccountManager* accountManager = AccountManager::Get(); + accountManager->SetNickname(fNickname->Text()); + break; + } + case kSetStatus: + { + int32 status; + + if (msg->FindInt32("status", &status) != B_OK) + return; + + AccountManager* accountManager = AccountManager::Get(); + accountManager->SetStatus((CayaStatus)status, ""); + break; + } + default: + BView::MessageReceived(msg); + } +} + + +void +StatusView::SetName(BString name) +{ + fNickname->SetText(name.String()); +} + + +void +StatusView::SetStatus(CayaStatus status) +{ + for (int32 i = 0; i < fStatusMenu->CountItems(); i++) { + StatusMenuItem* item + = reinterpret_cast(fStatusMenu->ItemAt(i)); + if (item && item->Status() == status && !item->IsCustom()) + item->SetMarked(true); + } +} + + +void +StatusView::SetAvatar(BBitmap* bitmap) +{ + BBitmap* b = RescaleBitmap(bitmap, 49, 49); + fAvatar->SetBitmap(b); +} diff --git a/application/views/StatusView.h b/application/views/StatusView.h new file mode 100644 index 0000000..1db2c6a --- /dev/null +++ b/application/views/StatusView.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _STATUS_VIEW_H +#define _STATUS_VIEW_H + +#include + +#include "CayaConstants.h" + +class BPopUpMenu; + +class BitmapView; +class NicknameTextControl; + +class StatusView : public BView { +public: + StatusView(const char* name); + + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage* msg); + + void SetName(BString name); + void SetStatus(CayaStatus status); + void SetAvatar(BBitmap* bitmap); + +private: + BPopUpMenu* fStatusMenu; + NicknameTextControl* fNickname; + BitmapView* fAvatar; +}; + +#endif // _STATUS_VIEW_H diff --git a/build/jam/BuildSettings b/build/jam/BuildSettings new file mode 100644 index 0000000..06d6b0b --- /dev/null +++ b/build/jam/BuildSettings @@ -0,0 +1,113 @@ +# BuildSettings +# +# Setup global variables. + +# C and C++ flags +if $(OSPLAT) = PPC { + # filter out -nosyspath + CFLAGS = [ FFilter $(CFLAGS) : -nosyspath ] ; + C++FLAGS = [ FFilter $(C++FLAGS) : -nosyspath ] ; + LINKFLAGS += -warn -export pragma ; +} + +# Use copyattr for copying. +CP = copyattr --data ; + +# Default paths for bison and flex: +BISON = bison ; +LEX = flex ; + +# mkdir shall not fail, if the directory already exists. +MKDIR = mkdir -p ; + +# by default we do not strip and do not build tests: +STRIP_APPS ?= 0 ; +BUILD_TESTS ?= 0 ; + +# Enable debugging by default +DEBUG ?= 1 ; + +rule SetUpSubDirBuildSettings +{ + # SetUpSubDirBuildSettings ; + # + # Sets up the compiler flags and defines based on the WARNINGS, DEBUG, and + # OPTIMIZE variables. Also sets the locations for the targets (objects, + # libraries and executables). + # + # : Parameters as passed to the SubDir rule, i.e. the name of the + # TOP variable and the subdir tokens. + # + local dir = $(1) ; + + # warnings settings + if $(WARNINGS) != 0 { + if $(OSPLAT) = X86 { + CCFLAGS += -Wall -Wno-multichar -Wpointer-arith + -Wmissing-prototypes -Wcast-align -Wsign-compare ; + C++FLAGS += -Wall -Wno-multichar -Wno-ctor-dtor-privacy -Woverloaded-virtual + -Wconversion -Wpointer-arith -Wcast-align + -Wsign-compare -Wno-reorder -Wno-unknown-pragmas ; + } else { + CCFLAGS += -w on -requireprotos ; + } + } + + local gccString = ; + if $(IS_GCC4_PLATFORM) { + gccString += gcc4 ; + } else { + gccString += gcc2 ; + } + + local binModeString = ; + if $(DEBUG) && $(DEBUG) != 0 { + binModeString += debug ; + } else { + binModeString += release ; + } + + # debugging settings + if $(DEBUG) && $(DEBUG) != 0 { + OPTIMIZE = 0 ; + STRIP_APPS = 0 ; + DEFINES += DEBUG=$(DEBUG) BM_REF_DEBUGGING ; + CCFLAGS += -g ; + C++FLAGS += -g -fno-inline ; + LINKFLAGS += -g ; + } + + DISTRO_DIR = [ FDirName $(TOP) generated distro-$(OS:L)-$(OSPLAT:L)-$(gccString)-$(binModeString) ] ; + OBJECTS_DIR = [ FDirName $(TOP) generated objects-$(OS:L)-$(OSPLAT:L)-$(gccString)-$(binModeString) ] ; + + # optimization settings + if $(OPTIMIZE) = 0 { + if $(OSPLAT) = X86 { + OPTIM = -O0 ; + } else { + OPTIM = -O0 ; + } + } else { + if $(OSPLAT) = X86 { + OPTIM ?= -O3 -fstrict-aliasing ; + } else { + OPTIM ?= -O7 ; + } + } + + # setup objects location + local objdir = [ FDirName $(OBJECTS_DIR) $(dir[2-]) ] ; + SEARCH_SOURCE += $(objdir) ; + LOCATE_SOURCE = $(objdir) ; + LOCATE_TARGET = $(objdir) ; + + # setup main targets location + LOCATE_MAIN_TARGET ?= [ FDirName $(DISTRO_DIR) ] ; +} + +# The LOCATE_MAIN_TARGET variable shall be reset for each subdirectory. +AUTO_SET_UP_CONFIG_VARIABLES += LOCATE_MAIN_TARGET ; + +# Add the rules setting up the build settings for a subdirectory to the +# rules invoked by SubDir. +SUBDIRRULES += SetUpSubDirBuildSettings ; diff --git a/build/jam/CheckRules b/build/jam/CheckRules new file mode 100644 index 0000000..b5106d9 --- /dev/null +++ b/build/jam/CheckRules @@ -0,0 +1,104 @@ +# CheckRules +# +# Common checks. + +rule CheckGccPlatform +{ + # CheckGccPlatform ; + # Detects if we are using gcc4 and set IS_GCC4_PLATFORM according. + + # First find out which gcc version the platform uses. + IS_GCC4_PLATFORM = ; + if $(OS) = HAIKU { + # Only Haiku might use gcc 4. We use the existence of a libstdc++.r4.so in + # /boot/develop/lib/x86 to judge whether this is a BeOS compatible and thus + # gcc 2 platform. This is not entirely correct, but should be good enough + # for the time being. + local haveLibStdC++.R4 = [ Glob /boot/develop/lib/x86 : libstdc++.r4.so ] ; + if ! $(haveLibStdC++.R4) { + IS_GCC4_PLATFORM = 1 ; + Echo Using GCC4 platform ; + } + } +} + +rule CheckOpenSSL +{ + # CheckOpenSSL ; + # Check for OpenSSL and defined HAVE_OPENSSL according, it also defines + # OPENSSL_INCLUDE_DIR and OPENSSL_LIBRARY_DIR with location of respectively + # include and library files. + + HAVE_OPENSSL = ; + OPENSSL_INCLUDE_DIR = ; + OPENSSL_LIBRARY_DIR = ; + + local haveHeaders = [ Glob $(COMMON_INCLUDE_DIRECTORY)/openssl : ssl.h ] ; + if $(haveHeaders) { + OPENSSL_INCLUDE_DIR = $(COMMON_INCLUDE_DIRECTORY)/openssl ; + + local haveLibs = [ Glob $(COMMON_LIB_DIRECTORY) : libssl.so ] ; + if $(haveLibs) { + OPENSSL_LIBRARY_DIR = $(COMMON_LIB_DIRECTORY) ; + + Echo OpenSSL Headers: $(OPENSSL_INCLUDE_DIR) ; + Echo OpenSSL Libs: $(OPENSSL_LIBRARY_DIR) ; + } + + HAVE_OPENSSL = $(haveLibs) ; + } +} + +rule CheckLibYahoo2 +{ + # CheckLibYahoo2 + # Check for LibYahoo2 and defined HAVE_LIBYAHOO2 according, it also defines + # LIBYAHOO2_INCLUDE_DIR and LIBYAHOO2_LIBRARY_DIR with location of respectively + # include and library files. + + HAVE_LIBYAHOO2 = ; + LIBYAHOO2_INCLUDE_DIR = ; + LIBYAHOO2_LIBRARY_DIR = ; + + local haveHeaders = [ Glob $(COMMON_INCLUDE_DIRECTORY)/libyahoo2 : yahoo2.h ] ; + if $(haveHeaders) { + LIBYAHOO2_INCLUDE_DIR = $(COMMON_INCLUDE_DIRECTORY)/libyahoo2 ; + + local haveLibs = [ Glob $(COMMON_LIB_DIRECTORY) : libyahoo2.so ] ; + if $(haveLibs) { + LIBYAHOO2_LIBRARY_DIR = $(COMMON_LIB_DIRECTORY) ; + + Echo Yahoo Headers: $(LIBYAHOO2_INCLUDE_DIR) ; + Echo Yahoo Libs: $(LIBYAHOO2_LIBRARY_DIR) ; + } + + HAVE_LIBYAHOO2 = $(haveLibs) ; + } +} + +rule CheckInfoPopper +{ + # CheckInfoPopper + # Check for InfoPopper and defined HAVE_INFOPOPPER according, it also defines + # INFOPOPPER_INCLUDE_DIR and INFOPOPPER_LIBRARY_DIR with location of respectively + # include and library files. + + HAVE_INFOPOPPER = ; + INFOPOPPER_INCLUDE_DIR = ; + INFOPOPPER_LIBRARY_DIR = ; + + local haveHeaders = [ Glob $(COMMON_INCLUDE_DIRECTORY)/infopopper : InfoPopper.h ] ; + if $(haveHeaders) { + INFOPOPPER_INCLUDE_DIR = $(COMMON_INCLUDE_DIRECTORY)/infopopper ; + + local haveLibs = [ Glob $(COMMON_LIB_DIRECTORY) : libinfopopper.so ] ; + if $(haveLibs) { + INFOPOPPER_LIBRARY_DIR = $(COMMON_LIB_DIRECTORY) ; + + Echo InfoPopper Headers: $(INFOPOPPER_INCLUDE_DIR) ; + Echo InfoPopper Libs: $(INFOPOPPER_LIBRARY_DIR) ; + } + + HAVE_INFOPOPPER = $(haveLibs) ; + } +} diff --git a/build/jam/ConfigRules b/build/jam/ConfigRules new file mode 100644 index 0000000..082ec46 --- /dev/null +++ b/build/jam/ConfigRules @@ -0,0 +1,146 @@ +# ConfigRules +# +# Contains rules providing the config variable feature. It allows to set the +# values for certain variables for subdirectories in a central place. That is +# one can, for instance, specify in a file like UserBuildConfig for which +# directories to enable debugging, warnings, set special defines, compiler +# flags and the like without needing to edit the Jamfiles for the respective +# dirs. + +rule ConfigObject +{ + # ConfigObject ; + # + # Private rule. Returns the dummy object on which the config variables are + # set for a given subdir. + # + # : Parameters as passed to the SubDir rule, i.e. the name of the + # TOP variable and the subdir tokens. + # + local config = __config__ ; + local grist = [ FGrist root $(1) ] ; + return $(config:G=$(grist)) ; +} + +rule SetConfigVar +{ + # SetConfigVar : : [ : ] ; + # + # Sets a config variable for a specified directory to the given value. + # + # : The name of the variable to be set. + # : Parameters as passed to the SubDir rule, i.e. the name of the + # TOP variable and the subdir tokens. + # : The value to which the variable shall be set. + # : Either "global" or "local". The former implies that the variable + # value shall also be used for subdirectories (recursively), if + # for them the variable has not been set. The latter has the same + # effect regarding subdirs as if the variable for the directory + # is not set. Defaults to "global". + # + local var = $(1[1]) ; + local config = [ ConfigObject $(2) ] ; + local scope = $(4) ; + if ! $(scope) { + scope = global ; + } + $(var) on $(config) = $(3) ; + __set_$(var) on $(config) = $(scope) ; +} + +rule AppendToConfigVar +{ + # AppendToConfigVar : : [ : ] ; + # + # Appends a value to a config variable for a specified directory. Shortcut + # for + # SetConfigVar : : [ ConfigVar : ] ; + # + # : The name of the variable to be set. + # : Parameters as passed to the SubDir rule, i.e. the name of the + # TOP variable and the subdir tokens. + # : The value which to append to the variables current value. + # : Either "global" or "local". The former implies that the variable + # value shall also be used for subdirectories (recursively), if + # for them the variable has not been set. The latter has the same + # effect regarding subdirs as if the variable for the directory + # is not set. Defaults to "global". + # + SetConfigVar $(1) : $(2) : [ ConfigVar $(1) : $(2) ] $(3) : $(4) ; +} + +rule ConfigVar +{ + # ConfigVar : [ : ] ; + # + # Returns the value of a configuration variable for a given subdir. + # If the variable is not set for the subdir, the rule is invoked + # recursively for the parent directory with the scope "global". When + # the root is reached without yielding a value, the value of the global + # variable is returned. + # + # : The name of the variable whose value shall be returned. + # : Parameters as passed to the SubDir rule, i.e. the name of the + # TOP variable and the subdir tokens. + # : If not given any scope passed to SetConfigVar for the given + # directory will be accepted, otherwise it must match the scope + # passed to SetConfigVar. + # + local var = $(1[1]) ; + local dir = $(2) ; + local config = [ ConfigObject $(dir) ] ; + local scope = $(3) ; + local varScope = [ on $(config) return $(__set_$(var)) ] ; + if ( ! $(scope) && $(varScope) ) + || ( $(scope) && $(scope) = $(varScope) ) + || ! $(dir) { + on $(config) return $($(var)) ; + } else { + dir = [ FReverse $(dir) ] ; + return [ ConfigVar $(var) : [ FReverse $(dir[2-]) ] : global ] ; + } +} + +rule SetUpConfigVars { + # SetUpConfigVars ; + # + # Sets the global variables defined in AUTO_SET_UP_CONFIG_VARIABLES to the + # values specified for the subdirectory . + # + # : Parameters as passed to the SubDir rule, i.e. the name of the + # TOP variable and the subdir tokens. + # + local dir = $(1) ; + + # Backup the global variable value on first invocation, otherwise restore + # them, so that ConfigVar returns the right values for not explicity set + # local variables. + local var ; + if ! $(__config_var_backup__) { + __config_var_backup__ = true ; + for var in $(AUTO_SET_UP_CONFIG_VARIABLES) { + __config_var_backup_$(var)__ = $($(var)) ; + } + } else { + for var in $(AUTO_SET_UP_CONFIG_VARIABLES) { + $(var) = $(__config_var_backup_$(var)__) ; + } + } + + # Set the variables to their configured values. + for var in $(AUTO_SET_UP_CONFIG_VARIABLES) { + $(var) = [ ConfigVar $(var) : $(dir) ] ; + } +} + +# Add the SetUpConfigVars rule to the rules that are invoked at the end of the +# SubDir rule. Prepend it, so that the variables are set up before any other +# rule is invoked. +SUBDIRRULES = SetUpConfigVars $(SUBDIRRULES) ; + +# Some config variables that should be set up automatically for subdirs. +AUTO_SET_UP_CONFIG_VARIABLES += + CCFLAGS C++FLAGS DEBUG DEFINES HDRS LINKFLAGS OPTIM OPTIMIZE + SYSHDRS WARNINGS +; diff --git a/build/jam/DistroRules b/build/jam/DistroRules new file mode 100644 index 0000000..e8b94a0 --- /dev/null +++ b/build/jam/DistroRules @@ -0,0 +1,35 @@ +# DistroRules +# +# Rules to archive binary distributions. + +rule Distro +{ + local target = $(1) ; + + NotFile $(target) ; + Always $(target) ; +} + +actions Distro +{ + echo "== Making distro $(DISTRO_DIR) ==" ; + mimeset $(DISTRO_DIR) ; +} + +Depends fulldistro : distro ; + +rule FullDistro +{ + local target = $(1) ; + + NotFile $(target) ; + Always $(target) ; +} + +actions FullDistro +{ + echo "== Making full distro $(FULL_DISTRO_DIR) ==" ; + rm -rf $(FULL_DISTRO_DIR) ; + cp -a $(DISTRO_DIR) $(FULL_DISTRO_DIR) ; + mimeset $(FULL_DISTRO_DIR) ; +} diff --git a/build/jam/FileRules b/build/jam/FileRules new file mode 100644 index 0000000..f13ff3d --- /dev/null +++ b/build/jam/FileRules @@ -0,0 +1,31 @@ +# FileRules +# +# Rules for files and symbolic links. + +rule SymLink +{ + # SymLink : : ; + # Links to . + # is the exact link contents. No binding is done. + # If true, will be made a dependency + # of the `all' pseudo target, i.e. it will be made by default, and removed + # on `jam clean'. + + local target = $(1) ; + local source = $(2) ; + local makeDefaultDependencies = $(3) ; + if ! $(makeDefaultDependencies) { + makeDefaultDependencies = true ; + } + LINKCONTENTS on $(target) = $(source) ; + SymLink1 $(target) ; + if $(makeDefaultDependencies) = true { + LocalDepends files : $(target) ; + LocalClean clean : $(target) ; + } +} + +actions SymLink1 +{ + $(RM) "$(1)" && $(LN) -s "$(LINKCONTENTS)" "$(1)" +} diff --git a/build/jam/HelperRules b/build/jam/HelperRules new file mode 100644 index 0000000..0876ddf --- /dev/null +++ b/build/jam/HelperRules @@ -0,0 +1,52 @@ +# HelperRules +# +# Helper rules without side effects. + +rule FFilter +{ + # FFilter : ; + # + # Removes all occurrences of in . + + local list = $(1) ; + local excludes = $(2) ; + local newList ; + local item ; + for item in $(list) { + local skip ; + local exclude ; + for exclude in $(excludes) { + if $(item) = $(exclude) { + skip = true ; + } + } + if ! $(skip) { + newList += $(item) ; + } + } + return $(newList) ; +} + +rule FSplitPath +{ + # FSplitPath ; + # + # Decomposes a path into its components. + # + # : The path to be decomposed. + # + local path = $(1:G=) ; + + local components ; + # $(path:D) for "/" is "/". Therefore the second condition. + while $(path:D) && $(path:D) != $(path) + { + # Note: $(path:B) returns "." for "..", but $(path:D=) is fine. + components = $(path:D=) $(components) ; + path = $(path:D) ; + } + components = $(components) ; + # Use this to return initial / + #components = $(path) $(components) ; + return $(components) ; +} diff --git a/build/jam/InstallRules b/build/jam/InstallRules new file mode 100644 index 0000000..80be960 --- /dev/null +++ b/build/jam/InstallRules @@ -0,0 +1,27 @@ +# InstallRules +# +# Missing rules for installation. + +rule InstallSymLink +{ + # InstallSymlink linkname : source ; + + LocalDepends install : $(>) ; + LocalDepends install : $(<) ; + LocalClean uninstall : $(<) ; + + NoCare $(>) ; + InstallSymLink1 $(<) : $(>) ; +} + +actions InstallSymLink1 +{ + $(RM) $(<) && $(LN) -s $(>) $(<) +} + +rule UninstallTarget +{ + # UninstallTarget target ; + + LocalClean uninstall : $(<) ; +} diff --git a/build/jam/MainBuildRules b/build/jam/MainBuildRules new file mode 100644 index 0000000..292a2a5 --- /dev/null +++ b/build/jam/MainBuildRules @@ -0,0 +1,380 @@ +# MainBuildRules +# +# Rules that specify what to build and how to do it. + +rule AddResources +{ + # AddResources : ; + # + # Adds resources to the application. + # + # : Name of the application. + # : List of resource files. Grist will be set. + # + local resfiles ; + local file ; + for file in $(2) { + if ! $(file:G) { + file = [ FGristFiles $(file) ] ; + } + resfiles += $(file) ; + } + + SEARCH on $(resfile) += $(SEARCH_SOURCE) ; + + for file in $(resfiles) { + if $(file:S) = .rdef { + local rdef = $(file) ; + file = $(rdef:S=.rsrc) ; + ResComp $(file) : $(rdef) ; + } + RESFILES on $(1) += $(file) ; + } +} + +rule Application +{ + # Application : : : ; + # + # Creates an application from sources. + # + # : Name of the application. Grist is allowed. + # : List of source files. Grist will be set. + # : List of libraries to link against. + # : List of resource files. Grist will be set. + # + local app = $(1) ; + local sources = $(2) ; + local libs = $(3) ; + local res = $(4) ; + + AddResources $(app) : $(res) ; + Main $(app) : $(sources) ; + MakeLocate $(app) : $(LOCATE_MAIN_TARGET) ; + LinkAgainst $(app) : $(libs) ; +} + +actions Strip +{ + strip "$(1)" ; +} + +rule AddOn +{ + # AddOn : : : ; + # + # Creates an add-on from sources. + # + # : Name of the add-on. Grist is allowed. + # : List of source files. Grist will be set. + # : List of libraries to link against. + # : List of resource files. Grist will be set. + # + SharedLibrary $(1) : $(2) : $(3) : $(4) ; +} + +rule SharedLibrary +{ + # SharedLibrary : : : ; + # + # Creates a shared library from sources. + # + # : Name of the shared library. Grist is allowed. + # : List of source files. Grist will be set. + # : List of libraries to link against. + # : List of resource files. Grist will be set. + # + local lib = $(1) ; + local sources = $(2) ; + local libs = $(3) ; + local res = $(4) ; + + AddResources $(lib) : $(res) ; + Main $(lib) : $(sources) ; + MakeLocate $(lib) : $(LOCATE_MAIN_TARGET) ; + local linkFlags ; + if $(OSPLAT) = X86 { + linkFlags = -nostart -Xlinker -soname=\"$(lib)\" -Xlinker --no-undefined ; + } else { + linkFlags = -xms ; + } + LINKFLAGS on $(lib) = [ on $(lib) return $(LINKFLAGS) ] $(linkFlags) ; + LinkAgainst $(lib) : $(libs) ; +} + +rule StaticLibrary +{ + # StaticLibrary : ; + # + # Creates a static library from sources. + # + # : Name of the static library. Grist is allowed. + # : List of source files. Grist will be set. + # + local lib = $(1) ; + Library $(lib) : $(2) ; + MakeLocate $(lib) : $(LOCATE_MAIN_TARGET) ; + + # If KEEPOBJS is set, Library doesn't make the library depend on `lib'. + if $(KEEPOBJS) { + Depends lib : $(lib) ; + } +} + +rule LinkAgainst +{ + # LinkAgainst : ; + # + # Adds libraries to the list of libraries a (Main) target shall be linked + # against. + # + # : The name of the target for which to add libraries. + # : The libraries (actually arbitrary shared objects and static + # libraries) to be added. Valid elements are e.g. "be" or + # "libopenbeos.so" or "/boot/.../libfoo.so". If the basename starts + # with "lib" or the thingy has a dirname or grist, it is added to + # the NEEDLIBS variable (i.e. the file will be bound!), otherwise + # it is prefixed "-l" and added to LINKLIBS. If you want to specify + # a target that isn't a library and also has neither grist nor a + # dirname, you can prepend "" as grist; it will be + # stripped by this rule. + # + for i in $(>) + { + local isfile = ; + if $(i:D) || $(i:G) { + isfile = true ; + if $(i:G) = { + i = $(i:G=) ; + } + } else { + switch $(i:B) + { + # XXX: _APP_ and _KERNEL_ should not be needed for ELF. + case _APP_ : isfile = true ; + case _KERNEL_ : isfile = true ; + case lib* : isfile = true ; + case * : isfile = ; + } + if ! $(isfile) && ( $(i:S) = .so || $(i:S) = .o || $(i:S) = .a ) { + isfile = true ; + } + } + if $(isfile) { + NEEDLIBS on $(1) = [ on $(1) return $(NEEDLIBS) ] $(i) ; + Depends $(1) : $(i) ; + } else { + LINKLIBS on $(1) = [ on $(1) return $(LINKLIBS) ] -l$(i) ; + } + } +} + +rule XRes +{ + # XRes : ; + # + # Adds resources to a file. + # + # : The files to which resources shall be added. + # : The resource files. + # + if $(2) + { + Depends $(1) : $(2) ; + XRes1 $(1) : $(2) ; + } +} + +rule ResComp +{ + # ResComp : ; + # + # Creates a binary resource file from a rdef script. + # + # : The resource file. Grist is required. + # : The rdef script. Grist is required. + # + local defines ; + + on $(1) { + defines = $(DEFINES) ; + } + + DEFINES on $(1) = $(defines) ; + CCDEFS on $(1) = [ FDefines $(defines) ] ; + HDRS on $(1) = [ on $(1) FIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ] + $(HDRS_INCLUDES_SEPARATOR) ; + RCHDRS on $(1) = [ FRcIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ] ; + + SEARCH on $(2) += $(SEARCH_SOURCE) ; + MakeLocate $(1) : $(LOCATE_TARGET) ; + Depends $(1) : $(2) $(RC) ; + LocalClean clean : $(1) ; + ResComp1 $(1) : $(RC) $(2) ; +} + +# Note: We pipe the input files into the preprocessor, since *.rdef files are +# considered linker scripts, and thus we can use preprocessor features. +actions ResComp1 +{ + cat "$(2[2-])" | $(CC) -E $(CCDEFS) $(HDRS) - | egrep -v '^#' | $(2[1]) $(RCHDRS) --auto-names -o "$(1)" - +} + +actions XRes1 +{ + xres -o "$(1)" "$(2)" ; +} + +actions MimeSet +{ + mimeset -f "$(1)" ; +} + +rule LexC++ +{ + Depends $(1) : $(2) ; + MakeLocate $(1) : $(LOCATE_SOURCE) ; + Clean clean : $(1) ; +} + +actions LexC++ +{ + $(LEX) -i -P$(<:B) -o$(1) $(2) +} + +rule Bison +{ + local _h ; + + _h = $(1:S=.h) ; + + MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ; + + Depends $(<) : $(>) ; + BisonC++ $(<) : $(>) ; + Clean clean : $(<) $(_h) ; + + # make sure someone includes $(_h) else it will be + # a deadly independent target + + Includes $(<) : $(_h) ; +} + +actions BisonC++ +{ + $(BISON) -v -d -p $(2:B) -o $(1) $(2) +} + +rule Rez +{ + Depends $(<) : $(>) ; +} + +rule PreCompile +{ + # PreCompile : + # + # precompiles the given src (a headerfile) into the specified header. + # + local _hdr = $(1) ; + local _src = $(2) ; + MakeLocate $(_hdr) : $(LOCATE_TARGET) ; + PreComp $(_hdr) : $(_src) ; + Clean clean : $(_hdr) ; +} + +rule PreComp +{ + Depends $(<) : $(>) ; +} + +actions PreComp +{ + mwcc -precompile $(<) -lang cplus "$(>)" ; +} + +rule SubDirSysHdrs +{ + # SubDirSysHdrs ; + # + # Adds directories to the system include search paths for the current + # subdirectory. Counterpart of SubDirHdrs which adds non-system include + # search paths. + # + # : The directories to be added to the current subdir's system + # include search paths. + # + SUBDIRSYSHDRS += [ FDirName $(1) ] ; +} + +rule ObjectSysHdrs +{ + # SubDirSysHdrs : ; + # + # Adds directories to the system include search paths for the given + # sources or objects. Counterpart of ObjectHdrs which adds non-system + # include search paths. + # + # NOTE: This rule must be invoked *after* the rule that generates the + # objects. + # + # : The targets for which to add system include + # search paths. + # : The directories to be added to the given objects' system + # include search paths. + # + + local s ; + for s in [ FGristFiles $(<:S=$(SUFOBJ)) ] { + SYSHDRS on $(s) += $(>) ; + CCHDRS on $(s) = [ on $(s) FIncludes $(HDRS) ] + $(HDRS_INCLUDES_SEPARATOR) [ on $(s) FSysIncludes $(SYSHDRS) ] ; + } +} + + +# FSysIncludes ; +# +# Counterpart of FIncludes for system include search paths. +# +if $(OSPLAT) = X86 { + rule FSysIncludes { return -I$(<) ; } +} else { + rule FSysIncludes { return "-i "$(<) ; } +} + +# FRcIncludes ; +# +# Counterpart of FIncludes for *.rdef scripts. +# +rule FRcIncludes +{ + return "-I "$(<) ; +} + +# Variable referring to the STL. +if $(OSPLAT) = X86 { + if $(IS_GCC4_PLATFORM) = 1 { + TARGET_LIBSTDC++ = stdc++ ; + } else { + TARGET_LIBSTDC++ = stdc++.r4 ; + } +} else { + TARGET_LIBSTDC++ = mslcpp_4_0 ; +} + + +rule CreateSVNRevisionFile file +{ + # CreateSVNRevisionFile + + local svnEntries = entries ; + SEARCH on $(svnEntries) = [ FDirName $(TOP) .svn ] ; + Depends $(file) : $(svnEntries) ; +} + +actions CreateSVNRevisionFile +{ + (LANG=C svn info $(TOP) 2> /dev/null || echo Revision: 0) | + grep Revision | awk '{printf $2}' > $(1) +} diff --git a/build/jam/OverriddenJamRules b/build/jam/OverriddenJamRules new file mode 100644 index 0000000..7a5acbf --- /dev/null +++ b/build/jam/OverriddenJamRules @@ -0,0 +1,218 @@ +# OverriddenJamRules +# +# Jam rules that need to be overridden for good reasons. + +# Overridden to allow for spaces in file names and to support resources. +# Also set the on target LINKFLAGS variable to prevent later changes to +# the global variable from having an effect on the setting for the target. +rule Link +{ + local dbg = [ on $(1) return $(DEBUG) ] ; + if $(STRIP_APPS) && $(STRIP_APPS) != 0 && (!$(dbg) || $(dbg) = 0) { + # strip app if requested so and if not in debug mode! + Strip $(1) ; + } + # Note: RESFILES must be set before invocation. + MODE on $(1) = $(EXEMODE) ; + on $(1) XRes $(1) : $(RESFILES) ; + Chmod $(1) ; + MimeSet $(1) ; + LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ] ; +} + +actions Link bind NEEDLIBS +{ + $(LINK) $(LINKFLAGS) -o "$(1)" $(UNDEFS) "$(2)" "$(NEEDLIBS)" $(LINKLIBS) +} + + +# Overridden to allow for spaces in file names. +actions Chmod1 +{ + $(CHMOD) "$(MODE)" "$(1)" +} + +# Overridden to allow for spaces in file names. +actions piecemeal together existing Clean +{ + $(RM) -rf "$(>)" +} + +# Changes to rules for sake of discrimination between system and non-system +# headers. + +if $(OSPLAT) = X86 { + if $(IS_GCC4_PLATFORM) = 1 { + HDRS_INCLUDES_SEPARATOR = -iquote- ; + } else { + HDRS_INCLUDES_SEPARATOR = -I- ; + } +} else { + HDRS_INCLUDES_SEPARATOR = -i- ; +} + +rule Cc +{ + Depends $(<) : $(>) ; + + # If the compiler's -o flag doesn't work, relocate the .o + + if $(RELOCATE) + { + CcMv $(<) : $(>) ; + } + + # Just to clarify here: this sets the per-target CCFLAGS to + # be the current value of (global) CCFLAGS and SUBDIRCCFLAGS. + # CCHDRS and CCDEFS must be reformatted each time for some + # compiles (VMS, NT) that malign multiple -D or -I flags. + + CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) $(OPTIM) ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] + $(HDRS_INCLUDES_SEPARATOR) [ on $(<) FSysIncludes $(SYSHDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +rule C++ +{ + Depends $(<) : $(>) ; + + if $(RELOCATE) + { + CcMv $(<) : $(>) ; + } + + C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) $(OPTIM) ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] + $(HDRS_INCLUDES_SEPARATOR) [ on $(<) FSysIncludes $(SYSHDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +rule Object +{ + # locate object and search for source, if wanted + + Clean clean : $(<) ; + + MakeLocate $(<) : $(LOCATE_TARGET) ; + SEARCH on $(>) = $(SEARCH_SOURCE) ; + + # Save HDRS for -I$(HDRS) on compile. + # We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers + # in the .c file's directory, but generated .c files (from + # yacc, lex, etc) are located in $(LOCATE_TARGET), possibly + # different from $(SEARCH_SOURCE). + + HDRS on $(<) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ; + SYSHDRS on $(<) = $(SUBDIRSYSHDRS) $(SYSHDRS) ; + + # handle #includes for source: Jam scans for headers with + # the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE) + # with the scanned file as the target and the found headers + # as the sources. HDRSEARCH is the value of SEARCH used for + # the found header files. Finally, if jam must deal with + # header files of the same name in different directories, + # they can be distinguished with HDRGRIST. + + # $(SEARCH_SOURCE:E) is where cc first looks for #include + # "foo.h" files. If the source file is in a distant directory, + # look there. Else, look in "" (the current directory). + + HDRRULE on $(>) = HdrRule ; + HDRSCAN on $(>) = $(HDRPATTERN) ; + HDRSEARCH on $(>) = + $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(SYSHDRS) $(STDHDRS) ; + + HDRGRIST on $(>) = $(HDRGRIST) ; + + # propagate target specific-defines + + DEFINES on $(<) += $(DEFINES) ; + + # if source is not .c, generate .c with specific rule + + switch $(>:S) + { + case .asm : As $(<) : $(>) ; + case .c : Cc $(<) : $(>) ; + case .C : C++ $(<) : $(>) ; + case .cc : C++ $(<) : $(>) ; + case .cpp : C++ $(<) : $(>) ; + case .f : Fortran $(<) : $(>) ; + case .l : Cc $(<) : $(<:S=.c) ; + LexC++ $(<:S=.c) : $(>) ; + case .s : As $(<) : $(>) ; + case .y : Cc $(<) : $(<:S=.c) ; + Bison $(<:S=.c) : $(>) ; + case * : UserObject $(<) : $(>) ; + } +} + +rule ObjectHdrs +{ + local s ; + for s in [ FGristFiles $(<:S=$(SUFOBJ)) ] { + HDRS on $(s) += $(>) ; + CCHDRS on $(s) = [ on $(s) FIncludes $(HDRS) ] + $(HDRS_INCLUDES_SEPARATOR) [ on $(s) FSysIncludes $(SYSHDRS) ] ; + } +} + +# Override Jam 2.5rc3 MakeLocate and MkDir to deal more intelligently +# with grist set on the supplied directory name. +rule MakeLocate +{ + if $(2[1]) + { + local dir = $(2[1]) ; + if ! $(dir:G) { + dir = $(dir:G=dir) ; + } + LOCATE on $(1) = $(dir:G=) ; + Depends $(1) : $(dir) ; + MkDir $(dir) ; + } +} + +rule MkDir +{ + # If dir exists, don't update it + # Do this even for $(DOT). + + local dir = $(<) ; + if ! $(dir:G) { + dir = $(dir:G=dir) ; + } + + NoUpdate $(dir) ; + + if $(dir:G=) != $(DOT) && ! $($(dir:G=)-mkdir) { + local s ; + + # Cheesy gate to prevent multiple invocations on same dir + # MkDir1 has the actions + # Arrange for jam dirs + + $(dir:G=)-mkdir = true ; + MkDir1 $(dir) ; + Depends dirs : $(dir) ; + + # Recursively make parent directories. + # $(dir:P) = $(dir)'s parent, & we recurse until root + + s = $(dir:P) ; # parent keeps grist + + if $(s:G=) && $(s) != $(dir) { + Depends $(dir) : $(s) ; + MkDir $(s) ; + } else if $(s) { + NotFile $(s) ; + } + } +} + +# Add SUBDIRSYSHDRS to the variables that shall be reset automatically by the +# SubDir rule. +SUBDIRRESET += SYSHDRS ; diff --git a/build/jam/PackageRules b/build/jam/PackageRules new file mode 100644 index 0000000..7bf932c --- /dev/null +++ b/build/jam/PackageRules @@ -0,0 +1,247 @@ +# PackageRules +# +# Rules to create archives for binary distribution + +rule Copy +{ + if $(2) { + SEARCH on $(2) += $(SEARCH_SOURCE) ; + Depends $(1) : $(COPYATTR) $(2) ; + Copy1 $(1) : $(COPYATTR) $(2) ; + } +} + +actions Copy1 +{ + "$(2[1])" -d "$(2[2-])" "$(1)" +} + +rule Packages +{ + local packagenames = $(1) ; + local packagefiles = $(2) ; + local path = $(3) ; + for name in $(packagenames) { + Package $(name) : $(packagefiles) : $(path) ; + } +} + +rule FPackageConfigSubPath +{ + # FPackageConfigSubPath + # + local packagename = $(1) ; + + local configSubPath ; + on $(packagename) { + configSubPath = $(OS:L) $(OSPLAT:L) ; + + if $(DEBUG) = 0 { + configSubPath += release ; + } else { + configSubPath += debug_$(DEBUG) ; + } + } + + return $(configSubPath) ; +} + +rule Package +{ + local packagename = $(1) ; + local packagefiles = $(2) ; + local path = $(3) ; + + local configSubPath = [ FPackageConfigSubPath $(packagename) ] ; + #local packagezip = $(packagename:S=.zip:G=_packages) ; + local packagezip = $(packagename:S=-$(VERSION).zip:G=_packages) ; + local targetDir = [ FDirName $(PACKAGE_DIR) $(configSubPath) ] ; + local packagedir = [ FDirName $(targetDir) $(packagename) ] ; + + local installscript = install.sh ; + local packageinstallscript = $(installscript:G=_packages!$(packagename)) ; + local installzip = install.zip ; + local packageinstallzip = $(installzip:G=_packages!$(packagename)) ; + + local packageobjectdir = [ FDirName $(PACKAGE_OBJECT_DIR) + $(configSubPath) $(packagename) ] ; + local packagefiledir = [ FDirName $(packageobjectdir) $(path) ] ; + local packagefileinstallzip + = $(installzip:G=_package_objects!$(packagename)) ; + + # add the files to the install.zip + local packagefilegrist = [ FGrist _package_files $(packagename) $(path) ] ; + for file in $(packagefiles) { + if $(path[0]) = "boot" { + local packagefile = $(file:G=$(packagefilegrist)) ; + MakeLocate $(packagefile) : $(packagefiledir) ; + Copy $(packagefile) : $(file) ; + Clean cleanPackages : $(packagefile) ; + PackageInstallZip $(packagefileinstallzip) : $(packagefile) ; + } else { + local packagefile = $(file:G=_packages!$(packagename)) ; + MakeLocate $(packagefile) : $(packagedir) ; + Copy $(packagefile) : [ FGristFiles $(file) ] ; + Clean cleanPackages : $(packagefile) ; + Depends $(packagezip) : $(packagefile) ; + } + } + + # general setup for this package -- only on first invocation + if ! $(_setup_$(packagename)) { + _setup_$(packagename) = true ; + + NotFile $(packagename) ; + LocalDepends packages : $(packagename) ; + + MakeLocate $(packagezip) : $(targetDir) ; + MakeLocate $(packageinstallscript) : $(packagedir) ; + MakeLocate $(packageinstallzip) : $(packagedir) ; + MakeLocate $(packagefileinstallzip) : $(packageobjectdir) ; + + PackageInstallScript $(packageinstallscript) : $(packagedir) ; + LinkInstallZip $(packageinstallzip) : $(packagefileinstallzip) ; + Depends $(packagename) : $(packagezip) ; + PackageZip $(packagezip) : $(packagedir) + : $(packageinstallscript) $(packageinstallzip) ; + } + +} + +rule PackageSymLink +{ + # PackageSymLink : + # : + # + local packagename = $(1) ; + local symlinkPath = $(2) ; + local symlinkTarget = $(3) ; + + local configSubPath = [ FPackageConfigSubPath $(packagename) ] ; + + local symlinkDir = [ FReverse $(symlinkPath) ] ; + local symlink = $(symlinkDir[1]) ; + symlinkDir = [ FReverse $(symlinkDir[2-]) ] ; + local symlinkGrist = [ FGrist _package $(packagename) $(symlinkDir) ] ; + symlink = $(symlink:G=$(symlinkGrist)) ; + + if $(symlinkDir[1]) = boot { + local installzip = install.zip ; + local packagefileinstallzip + = $(installzip:G=_package_objects!$(packagename)) ; + + local packageobjectdir = [ FDirName $(PACKAGE_OBJECT_DIR) + $(configSubPath) $(packagename) ] ; + symlinkDir = [ FDirName $(packageobjectdir) $(symlinkDir) ] ; + + PackageInstallZip $(packagefileinstallzip) : $(symlink) ; + + } else { + #local packagezip = $(packagename:S=.zip:G=_packages) ; + local packagezip = $(packagename:S=-$(VERSION).zip:G=_packages) ; + + local packagedir = [ FDirName $(PACKAGE_DIR) $(configSubPath) + $(packagename) ] ; + symlinkDir = [ FDirName $(packagedir) $(symlinkDir) ] ; + + Depends $(packagezip) : $(symlink) ; + } + + MakeLocate $(symlink) : $(symlinkDir) ; + SymLink $(symlink) : $(symlinkTarget) : false ; + Clean cleanPackages : $(symlink) ; +} + +rule PackageDriverSymLink +{ + # PackageDriverSymLink : ; + # : Package name. + # : Path components relative to the + # /boot/home/config/add-ons/kernel/drivers/dev directory, e.g. + # "graphics mga.driver" (no quotation, of course). + # + local packageName = $(1) ; + local symlinkComponents = $(2) ; + + # construct the symlink contents + local symlinkPath = [ FReverse $(symlinkComponents) ] ; + symlinkPath = bin $(symlinkPath[1]) ; + + for i in $(symlinkComponents) { + symlinkPath = $(DOTDOT) $(symlinkPath) ; + } + + PackageSymLink $(packageName) + : boot home config add-ons kernel drivers dev $(symlinkComponents) + : [ FDirName $(symlinkPath) ] ; +} + +rule PackageZip +{ + local dir = $(2:G=dir) ; + Depends $(1) : $(dir) $(3) ; + Clean cleanPackages : $(1) ; + PackageZip1 $(1) : $(dir) ; +} + +actions together PackageZip1 { + cd "$(2:P)" ; + zip -rq "$(1:BS)" "$(2:BS)" ; +} + +rule PackageInstallScript +{ + MakeLocate $(1) : $(2) ; + Clean cleanPackages : $(1) ; + PackageInstallScript1 $(1) : $(2:G=dir) ; +} + +actions together PackageInstallScript1 +{ +echo '#!/bin/sh +base=`dirname "$0"` +cd "$base" +if [ -n "$TTY" ] +then + unzip -d / install.zip +else + response=`alert "Would you like to automatically overwrite existing files, or receive a prompt?" "Overwrite" "Prompt"` + if [ $response == "Overwrite" ] + then + unzip -od / install.zip + alert "Finished installing" "Thanks" + else + if [ -e /boot/beos/apps/Terminal ] + then + terminal=/boot/beos/apps/Terminal + else + terminal=`query Terminal | head -1` + fi + $terminal -t "installer" /bin/sh "$0" + fi +fi' > "$(1)" ; + chmod 755 "$(1)" ; +} + +rule PackageInstallZip +{ + Depends $(1) : $(2) ; + Clean cleanPackages : $(1) ; +} + +actions together PackageInstallZip +{ + cd "$(1:P)" ; + zip -rqy "$(1:BS)" boot ; +} + +rule LinkInstallZip +{ + Depends $(1) : $(2) ; + Clean cleanPackages : $(1) ; +} + +actions together LinkInstallZip +{ + ln -sf "`pwd`/$(2)" "$(1)" ; +} diff --git a/build/jam/UserBuildConfig.sample b/build/jam/UserBuildConfig.sample new file mode 100644 index 0000000..4d9280b --- /dev/null +++ b/build/jam/UserBuildConfig.sample @@ -0,0 +1,63 @@ +# UserBuildConfig +# +# Sample of a UserBuildConfig file. It is a central place where the user can +# set variables affecting certain aspects of the build, such as debug, +# warnings and optimization settings. +# +# The following variables can be set: +# +# BUILD_TESTS - If not empty, all tests (TestBeam) will be build, too. +# Default is 0, i.e. no tests. +# CCFLAGS, C++FLAGS - Flags passed to the C/C++ compiler. +# DEBUG - If not empty, will turn on debugging, i.e. will +# add respective C/C++ compiler and linker flags and +# the CPP DEBUG macro. +# DEFINES - CPP macros to be defined, e.g. something like +# `SPECIAL_FEATURE' or `CACHE_SIZE=1024'. +# HDRS - List of directories to be added to the local include +# search paths. +# LINKFLAGS - Flags passed to the linker. +# LOCATE_MAIN_TARGET - Directory where the main targets (i.e. applications, +# libraries shall be placed). Should usually not be +# tampered with by the user. +# OPTIM - Optimization specific flags passed to the C/C++ +# compiler. Usually you want to use OPTIMIZE instead. +# OPTIMIZE - If not set to `0', will turn on optimization, i.e. +# will set the respective C/C++ compiler flags +# (i.e. the OPTIM variable). +# STRIP_APPS - if not set to '0', will cause all generated apps to +# be stripped. Default is '0', i.e. no stripping +# SYSHDRS - List of directories to be added to the system include +# search paths. +# WARNINGS - If not set to `0', will turn on warnings, i.e. will +# set the respective C/C++ compiler flags. + +# Examples: + +# Globally turn off debugging: +# +# DEBUG = 0 ; + +# Globally activate debugging: +# +# DEBUG = 1 ; + +# ... e.g. like this, for the `add-ons/catalogs' directory and all its +# subdirectories. +# +# SetConfigVar WARNINGS : TOP add-ons catalogs : 1 ; + +# Turn on debugging for the the directory `Languages' and all its subdirectories. +# +# SetConfigVar DEBUG : TOP Languages : 1 ; + +# Turn off optimization for the `rez' directory and all its subdirectories. +# +# SetConfigVar OPTIMIZE : TOP rez : 0 ; + +# Define the CPP macro INSANE_DEBUGGING_LEVEL to the value `100' in the +# `lpe' directory, but NOT in its subdirectories (note the use of the +# optional fourth parameter `local', which works for both SetConfigVar and +# AppendToConfigVar). +# +# AppendToConfigVar DEFINES : TOP lpe : INSANE_DEBUGGING_LEVEL=100 : local ; diff --git a/configure b/configure new file mode 100755 index 0000000..dcbd57f --- /dev/null +++ b/configure @@ -0,0 +1,144 @@ +#!/bin/sh +# +# Copyright 2009, Pier Luigi Fiorini. +# Distributed under the terms of the MIT License. +# +# Authors: +# Pier Luigi Fiorini, pierluigi.fiorini@gmail.com +# + +current_dir=`pwd` +defines="" + +# Binaries +jambin=`which jam` +rcbin=`which rc` +xresbin=`which xres` +settypebin=`which settype` +mimesetbin=`which mimeset` +setversionbin=`which setversion` +copyattrbin=`which copyattr` + +# Check operating system +platform=`uname -s` +release=`uname -r` +echo -n "Checking operating system... " +case "$platform" in + BeOS) + case "$release" in + 4.*) + echo "*** BeOS R4 is not supported!" + exit 1 + ;; + 5.*) + echo "*** BeOS R5 is not supported!" + exit 1 + ;; + 6.*) + echo "*** Zeta is not supported!" + exit 1 + ;; + *) + echo "*** Unsupported BeOS platform!" + exit 1 + ;; + esac + ;; + Haiku) + defines="HAIKU_TARGET_PLATFORM_HAIKU=1" + ;; + *) + echo "*** Unsupported $platform operating system!" + exit 1 + ;; +esac +echo "$platform $release" + +# Check whether jam exists +echo -n "Checking whether jam exists... " +if [ -z "$jambin" ]; then + echo "not found" + echo "*** Caya requires jam, please read our Build.txt file." + exit 1 +else + echo "found" +fi + +# Check for rc +echo -n "Checking for rc... " +if [ -z "$rcbin" ]; then + echo "not found" + exit 1 +fi +echo $rcbin + +# Check for xres +echo -n "Checking for xres..." +if [ -z "$xresbin" ]; then + echo "not found" + exit 1 +fi +echo $xresbin + +# Check for settype +echo -n "Checking for settype..." +if [ -z "$settypebin" ]; then + echo "not found" + exit 1 +fi +echo $settypebin + +# Check for mimeset +echo -n "Checking for mimeset..." +if [ -z "$mimesetbin" ]; then + echo "not found" + exit 1 +fi +echo $mimesetbin + +# Check for setverion +echo -n "Checking for setversion..." +if [ -z "$setversionbin" ]; then + echo "not found" + exit 1 +fi +echo $setversionbin + +# Check for copyattr +echo -n "Checking for copyattr..." +if [ -z "$copyattrbin" ]; then + echo "not found" + exit 1 +fi +echo $copyattrbin + +# Create the build configuration +mkdir -p $current_dir/generated +cat > $current_dir/generated/BuildConfig << EOF +RC = ${rcbin} ; +XRES = ${xresbin} ; +SETTYPE = ${settypebin} ; +MIMESET = ${mimesetbin} ; +SETVERSION = ${setversionbin} ; +COPYATTR = ${copyattrbin} ; + +COMMON_DIRECTORY = $(finddir B_COMMON_DIRECTORY) ; +COMMON_BIN_DIRECTORY = $(finddir B_COMMON_BIN_DIRECTORY) ; +COMMON_INCLUDE_DIRECTORY = $(finddir B_COMMON_DIRECTORY)/include ; +COMMON_LIB_DIRECTORY = $(finddir B_COMMON_LIB_DIRECTORY) ; +COMMON_SERVERS_DIRECTORY = $(finddir B_COMMON_SERVERS_DIRECTORY) ; +COMMON_ADDONS_DIRECTORY = $(finddir B_COMMON_ADDONS_DIRECTORY) ; +COMMON_DEVELOP_DIRECTORY = $(finddir B_COMMON_DEVELOP_DIRECTORY) ; +USER_CONFIG_DIRECTORY = $(finddir B_USER_CONFIG_DIRECTORY) ; +USER_INCLUDE_DIRECTORY = $(finddir B_USER_CONFIG_DIRECTORY)/include ; +SYSTEM_DIRECTORY = $(finddir B_SYSTEM_DIRECTORY) ; +SYSTEM_LIB_DIRECTORY = $(finddir B_SYSTEM_LIB_DIRECTORY) ; +BEOS_PREFERENCES_DIRECTORY = $(finddir B_BEOS_PREFERENCES_DIRECTORY) ; +PREFERENCES_DIRECTORY = $(finddir B_PREFERENCES_DIRECTORY) ; +USER_PREFERENCES_DIRECTORY = $(finddir B_USER_CONFIG_DIRECTORY)/be/Preferences ; +APPS_DIRECTORY = $(finddir B_APPS_DIRECTORY) ; + +DEFINES += ${defines} ; +EOF + +echo "Configuration done." diff --git a/data/icons/misc/Search b/data/icons/misc/Search new file mode 100644 index 0000000000000000000000000000000000000000..8a2692053da46a6186abd63d74b64bfba63a3cd6 GIT binary patch literal 485 zcmc~x&P?NAWn^MtW45^T-R5HQ{-#aVEi1h{0z3*%GW>tPbnpK^2mb&6F@cGZjmgea zg#ip~R;}`MVDK_v_z#q=`M8~pg>e!SgBX)l=(1ghH0^m8+f8kAJM`Lp;WY-v|MNgv zZ6F#M7=R3*KCb`N~j6L7$7$I?^_J|JjpvuF*%uj($vVi*}B6bqVBRiE@gw zkFpJS;9$~q*e7ks!DQgHpJCTU4klxl{hRm5axj^>9Vpsc%E6@Otm(qU;$(Gbztz47 zD+?Ek{VEoRyPf>@Mfe@s@8{#85!a4=k3eN z#lXlVX37;Nk;1PejX(n1iiIKS_`ee2%EzzsLMH{Z;g|F@G)09(@AQv zd>NsT_K zT~gNVjejwYv*HDh6xEjy^gr&$?@I4I24eMb9 zKw25}3J1Em0v~XS!#1rk7nI59B>Gg+Eao_vMBI`+a-mW>PrH*T(}r8iVps?_HdGk# zewnLQCJcTDIR9ISoG<t+^G!yyDPU01dlh~kQ zv241;mSsW`IYGP_Mhz$N!vGr6k5T>Zd~U^c$6GH|POa}7r(4h0kG8_a#n@AKMVdp; z&Tjrb28U~-$!gP6TY!t?Ma{6TW3qLAQ1c=`u{+W!#5Jdh1^?CM6d%Hl?#%R90J~)< zzu@<2nCev+S?@9mXOQ0&de<{Ivm9)j8KW>5zgYPh4+G9bKlZQqbw63PW7ol#mDF%n{-;7U>LqQNX2SLOk{(kS>J1@~fKJq2`e&4_M{dsR@cA;{0cKW=4 z3gFHj^u8!!K|k1I15x=Eq$rij!YpI#@(aXJ1sTflPXi)fp~DY+{^GxZZST|eZ6|5O z@)<}!r@8|>e6mxStfq(pH0D&dX$Yc@S!BJ>B+uZ4>a!#az(9Ge~Y;oG@aQ)FXEoi+?t6VVzSk{a!) zLsI94LEyQGwT9qf{fR2E*{cyH@Z=gJx;%Y#{5SAln$@efEH*AIx z0O@4VYdG|C1wO!w!#1rk7nFz5hbXE;vzRkr5^+lo$(3sPGVRW#OdD=3i(w($*id1_ zhh(uzSKbj&#k8S(uD3R({4~z&PXlh2YC~0?e4byLA>g zE3;&O*X&m^`=e^Nn2S3V?}6V>adoZj$g4vZQ4fm|dLO@@xhMzuvB#Pi+}_f5_ErNE h_k(4TmLJ$_e(c}$n|`uk$F75ymDF<9|EJiT`~zHXOCkUO literal 0 HcmV?d00001 diff --git a/data/icons/status/Offline b/data/icons/status/Offline new file mode 100644 index 0000000000000000000000000000000000000000..9ed0a9252cf12f80c4009db6ce92c622e0c856ba GIT binary patch literal 1882 zcma)6KWGzC82{3yO>pCw@c24Xy2O21rLT)04a4;3J` z%7WM8+19r!h1^d(-YR#hCz_rW^Oh{BndypiI8)AZ0? z5!a90h9|Ai4-$w{5?PU%cl%=GsY(J3aSC3|f@8{l3k&PjB+AzGCh}P(k)M!r~ zk~%jG0?$pnB`JW|bK7l%G37W}Yk0AI>g#RJw_wK-*(MUp&r^Q;64)9Wl}1`UX8DE` z`5jLKsm#pAZ8C%2tCOUI!0yjgD?A|wG!EAGL)rGdgYrm-?bZMSfy;9j6f2ofa1SSC3PC3Oj}~(_;bb zmZAKDKcQi&S83#Nk6Ac_{H`#%p1GOjaL3G;g~|A0G7ZzhCVZb8)BQ9q@-KuCBEmc{Ru)>R~ZL_v6J#+>R74MEf~i>&sUMz7DT8u#ap5B6Jyd|$ zDhpnVbMqBcCN}s0n7)>bbm8ZLv#pklcH!57(U*9wURQA_-v{eBV+v1)k(5JVE5F4roTXm>Va+Hh-G3=84Lh6*D- zEQ|Hpw88HI=YI>Ci^V?!#@k}azApSFFr9b2YinO;xZ84)L=Ho$%*XzUlX~Uy3^u4- zu9_~fWx0^XPLMRhxb38V7(he%KB0emzyHN`$LBYeIvd+>JL8YebWSvmb;3p?@zh>3zPB1D$aNxFwVGmA^7qg0W)UrZk-0s z$}HL4HT#>n{UNnm%*CBbcEBHGxVqMM>@^^ZsE5S}y^mkdT$F?S*kMf!Zf|Nkd$Wm& h`@ynE+Yjs&Kk;w)Ek9ke6W77ZN@_c+|5L0_{sGdDO6C9n literal 0 HcmV?d00001 diff --git a/libs/Jamfile b/libs/Jamfile new file mode 100644 index 0000000..f5d58b5 --- /dev/null +++ b/libs/Jamfile @@ -0,0 +1,7 @@ +SubDir TOP libs ; + +# Include all the components. +SubInclude TOP libs libjabber ; +SubInclude TOP libs librunview ; +SubInclude TOP libs libinterface ; +SubInclude TOP libs libsupport ; diff --git a/libs/libinterface/BitmapMenuItem.cpp b/libs/libinterface/BitmapMenuItem.cpp new file mode 100644 index 0000000..6d6093b --- /dev/null +++ b/libs/libinterface/BitmapMenuItem.cpp @@ -0,0 +1,109 @@ +/* + BitmapListItem.cpp: A BMenuItem with an optional picture + Written by DarkWyrm , Copyright 2007 + Released under the MIT license. +*/ +#include "BitmapMenuItem.h" +#include + +BitmapMenuItem::BitmapMenuItem(const char *label, BMessage *msg, + BBitmap *bitmap, char shortcut, + uint32 modifiers) + : BMenuItem(label,msg,shortcut,modifiers), + fBitmap(bitmap) +{ +} + + +BitmapMenuItem::BitmapMenuItem(BMessage *data) + : BMenuItem(data) +{ + fBitmap = (BBitmap*) BBitmap::Instantiate(data); +} + + +BitmapMenuItem::~BitmapMenuItem(void) +{ + delete fBitmap; +} + + +status_t +BitmapMenuItem::Archive(BMessage *data, bool deep) const +{ + status_t status = BMenuItem::Archive(data,deep); + + if (status == B_OK && fBitmap) + status = fBitmap->Archive(data,deep); + + if (status == B_OK) + status = data->AddString("class","BitmapMenuItem"); + + return status; +} + + +void +BitmapMenuItem::GetContentSize(float *width, float *height) +{ + float w,h; + BMenuItem::GetContentSize(&w,&h); + if (fBitmap) + w += (fBitmap->Bounds().Width() * + (Frame().Height() / fBitmap->Bounds().Height())) + 20; + + if (width) + *width = w; + + if (height) + *height = h; +} + + +void +BitmapMenuItem::DrawContent(void) +{ + if (!Label() && !fBitmap) + return; + + float width, height; + GetContentSize(&width, &height); + + BRect drawrect(Frame()); + drawrect.bottom--; + drawrect.top++; + drawrect.left = ContentLocation().x; + if (fBitmap) { + // Scale the fBitmap down to completely fit within the field's height + if (fBitmap->Bounds().Height() > drawrect.Height()) { + drawrect.right = drawrect.left + + (fBitmap->Bounds().Width() * + (Frame().Height() / fBitmap->Bounds().Height())); + } else { + drawrect.right = drawrect.left + fBitmap->Bounds().Width(); + } + } else { + drawrect.right = drawrect.left - 5; + } + + BPoint stringpoint(ContentLocation()); + stringpoint.x = drawrect.right + 10; + Menu()->MovePenTo(stringpoint); + BMenuItem::DrawContent(); + + if (fBitmap) { + Menu()->PushState(); + Menu()->SetDrawingMode(B_OP_ALPHA); + Menu()->DrawBitmap(fBitmap, fBitmap->Bounds(), drawrect); + Menu()->PopState(); + } +} + + +void +BitmapMenuItem::SetBitmap(BBitmap *bitmap) +{ + delete fBitmap; + fBitmap = bitmap; +} + diff --git a/libs/libinterface/BitmapMenuItem.h b/libs/libinterface/BitmapMenuItem.h new file mode 100644 index 0000000..0988268 --- /dev/null +++ b/libs/libinterface/BitmapMenuItem.h @@ -0,0 +1,40 @@ +/* + BitmapListItem.h: A BMenuItem with an optional picture + Written by DarkWyrm , Copyright 2007 + Released under the MIT license. +*/ +#ifndef BITMAP_MENU_ITEM_H +#define BITMAP_MENU_ITEM_H + +#include + +/* + BitmapMenuItems are simple little items, really. They provide the + ability to show a menu item with some text, a picture, or both. The item + takes ownership of the BBitmap given to it, so please do not delete it. + Note that it is still possible to see the checkmark on marked + BitmapMenuItems -- the bitmap does not obscure the checkmark. +*/ + +class BitmapMenuItem : public BMenuItem +{ +public: + BitmapMenuItem(const char *label, BMessage *msg, + BBitmap *bitmap, char shortcut = 0, + uint32 modifiers = 0); + BitmapMenuItem(BMessage *data); + virtual ~BitmapMenuItem(void); + virtual status_t Archive(BMessage *data, bool deep = true) const; + + virtual void GetContentSize(float *width, float *height); + virtual void DrawContent(void); + + virtual void SetBitmap(BBitmap *bitmap); + BBitmap * Bitmap(void) const; + +private: + BBitmap *fBitmap; + float fBaselineOffset; +}; + +#endif diff --git a/libs/libinterface/BitmapUtils.cpp b/libs/libinterface/BitmapUtils.cpp new file mode 100644 index 0000000..d0da628 --- /dev/null +++ b/libs/libinterface/BitmapUtils.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include + +#include "BitmapUtils.h" + +#define BEOS_ICON_ATTRIBUTE "BEOS:ICON" +#define BEOS_MINI_ICON_ATTRIBUTE "BEOS:M:STD_ICON" +#define BEOS_LARGE_ICON_ATTRIBUTE "BEOS:L:STD_ICON" + + +BBitmap* +ReadNodeIcon(const char* name, icon_size size, bool followSymlink) +{ + BEntry entry(name, followSymlink); + entry_ref ref; + + entry.GetRef(&ref); + + BNode node(BPath(&ref).Path()); + + BBitmap* ret = new BBitmap(BRect(0, 0, (float)size - 1, (float)size - 1), B_RGBA32); + if (BIconUtils::GetIcon(&node, BEOS_ICON_ATTRIBUTE, BEOS_MINI_ICON_ATTRIBUTE, + BEOS_LARGE_ICON_ATTRIBUTE, size, ret) != B_OK) { + delete ret; + ret = NULL; + } + + return ret; +} + + +BBitmap* IconFromResources(BResources* res, int32 num, icon_size size) +{ + if (!res) + return NULL; + + size_t nbytes = 0; + type_code type = B_VECTOR_ICON_TYPE; + color_space cspace = B_RGBA32; + + // Try to find a vector icon + const void* data = res->LoadResource(type, num, &nbytes); + if (data == NULL) { + // Determine resource type from icon size + switch (size) { + case B_MINI_ICON: + type = B_MINI_ICON_TYPE; + break; + case B_LARGE_ICON: + type = B_LARGE_ICON_TYPE; + break; + default: + return NULL; + } + + // Get bitmap icon + data = res->LoadResource(type, num, &nbytes); + if (data == NULL) + return NULL; + + cspace = B_CMAP8; + } + + BBitmap* icon = new BBitmap(BRect(0, 0, size - 1, size - 1), cspace); + if (icon->InitCheck() != B_OK) + return NULL; + + switch (type) { + case B_VECTOR_ICON_TYPE: + if (BIconUtils::GetVectorIcon((const uint8*)data, nbytes, icon) != B_OK) { + delete icon; + return NULL; + } + break; + default: + icon->SetBits(data, size * size, 0, cspace); + } + + return icon; +} diff --git a/libs/libinterface/BitmapUtils.h b/libs/libinterface/BitmapUtils.h new file mode 100644 index 0000000..fc3c33e --- /dev/null +++ b/libs/libinterface/BitmapUtils.h @@ -0,0 +1,15 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _BITMAP_UTILS_H +#define _BITMAP_UTILS_H + +#include +#include +#include + +BBitmap* ReadNodeIcon(const char* name, icon_size size, bool followSymlink); +BBitmap* IconFromResources(BResources* res, int32 num, icon_size size); + +#endif // _BITMAP_UTILS_H diff --git a/libs/libinterface/BitmapView.cpp b/libs/libinterface/BitmapView.cpp new file mode 100644 index 0000000..f5a0b80 --- /dev/null +++ b/libs/libinterface/BitmapView.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include + +#include "BitmapView.h" + + +BitmapView::BitmapView(const char* name, uint32 flags) + : BView(name, flags), + fBitmap(NULL), + fWidth(0.0f), + fHeight(0.0f) +{ + // Set transparent + //SetViewColor(B_TRANSPARENT_COLOR); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + + +BitmapView::~BitmapView() +{ + delete fBitmap; + fBitmap = NULL; +} + + +status_t +BitmapView::InitCheck() +{ + if (fBitmap != NULL) + return B_OK; + return B_ERROR; +} + + +void +BitmapView::SetBitmap(BBitmap* bitmap) +{ + delete fBitmap; + fBitmap = bitmap; + + if (fBitmap != NULL) { + BRect frame(fBitmap->Bounds()); + + fWidth = frame.Width(); + fHeight = frame.Height(); + + ResizeTo(fWidth, fHeight); + } +} + + +BSize +BitmapView::MinSize() +{ + return BSize(fWidth, fHeight); +} + + +BSize +BitmapView::MaxSize() +{ + return MinSize(); +} + + +BSize +BitmapView::PreferredSize() +{ + return MinSize(); +} + + +void +BitmapView::Draw(BRect frame) +{ + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + + if (fBitmap != NULL) + DrawBitmap(fBitmap, BPoint(0, 0)); +} diff --git a/libs/libinterface/BitmapView.h b/libs/libinterface/BitmapView.h new file mode 100644 index 0000000..147e4f1 --- /dev/null +++ b/libs/libinterface/BitmapView.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _BITMAP_VIEW_H +#define _BITMAP_VIEW_H + +#include + +class BBitmap; + +class BitmapView : public BView { +public: + BitmapView(const char* name, uint32 flags = B_WILL_DRAW); + ~BitmapView(); + + status_t InitCheck(); + + void SetBitmap(BBitmap* bitmap); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + + virtual void Draw(BRect frame); + +private: + BBitmap* fBitmap; + float fWidth; + float fHeight; +}; + +#endif // _BITMAP_VIEW_H diff --git a/libs/libinterface/Divider.cpp b/libs/libinterface/Divider.cpp new file mode 100644 index 0000000..280d225 --- /dev/null +++ b/libs/libinterface/Divider.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include "Divider.h" + +const float kResizeWidgetRatio = 0.1f; +const float kResizeWidgetPadding = 2.0f; +const float kResizeWidgetCircleRadius = 2.0f; +const float kResizeWidgetSpacing = 10.0f; +const int kResizeWidgetCircleCount = 2; + + +Divider::Divider(const char* name, uint32 flags) + : BView(name, flags), + fOrient(B_HORIZONTAL) +{ + SetViewColor (ui_color (B_PANEL_BACKGROUND_COLOR)); +} + + +Divider::Divider(BMessage* archive) + : BView(archive) +{ + if (archive->FindInt32("orientation", (int32*)&fOrient) != B_OK) + fOrient = B_HORIZONTAL; +} + + +Divider::~Divider() +{ +} + + +void +Divider::Draw(BRect updateRect) +{ + BRect bounds = Bounds(); + + rgb_color view_color = ViewColor(); + + rgb_color line = tint_color(view_color, B_DARKEN_1_TINT); + rgb_color shadow = tint_color(view_color, B_DARKEN_2_TINT); + + PushState(); + + SetHighColor(view_color); + FillRect(bounds); + + if (fOrient == B_HORIZONTAL) { + BPoint left(bounds.left, (bounds.Height() / 2) + bounds.top); + BPoint right(bounds.right, left.y); + + BPoint fudge(PenSize(), PenSize()); + + left -= fudge; + right -= fudge; + SetHighColor(line); + StrokeLine(left, right); + + left += fudge; + right += fudge; + SetHighColor(shadow); + StrokeLine(left, right); + } else { + BPoint top((bounds.Width() / 2) + bounds.left, bounds.top); + BPoint bottom(top.x, bounds.bottom); + + BPoint fudge(PenSize(), PenSize()); + + top -= fudge; + bottom -= fudge; + SetHighColor(line); + StrokeLine(top, bottom); + + top += fudge; + bottom += fudge; + SetHighColor(shadow); + StrokeLine(top, bottom); + } + + PopState(); +} + + +void +Divider::GetPreferredSize(float* width, float* height) +{ + if (fOrient == B_HORIZONTAL) { + *width = Bounds().Width(); + *height = (PenSize() * 4); // Two widths for padding (either side) + line + shadow + } else { + *height = Bounds().Height(); + *width = (PenSize() * 4); // Two widths for padding (either side) + line + shadow + } +} + + +status_t +Divider::Archive(BMessage* archive, bool deep) const +{ + archive->AddInt32("orientation", fOrient); + return BView::Archive(archive, false); +} + + +BArchivable* +Divider::Instantiate(BMessage* archive) +{ + BArchivable *instance = NULL; + + if (validate_instantiation(archive, "Divider")) + instance = new Divider(archive); + + return instance; +} + + +orientation +Divider::Orientation() +{ + return fOrient; +} + + +void +Divider::Orientation(orientation orient) +{ + fOrient = orient; +} diff --git a/libs/libinterface/Divider.h b/libs/libinterface/Divider.h new file mode 100644 index 0000000..783db7b --- /dev/null +++ b/libs/libinterface/Divider.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _DIVIDER_H +#define _DIVIDER_H + +#include + +class BMessage; +class BMessenger; + +class Divider : public BView { +public: + Divider(const char* name, uint32 flags = B_FRAME_EVENTS | B_WILL_DRAW); + virtual ~Divider(); + + Divider(BMessage* archive); + + virtual void Draw(BRect updateRect); + virtual void GetPreferredSize(float* width, float* height); + + status_t Archive(BMessage* archive, bool deep = true) const; + + static BArchivable* Instantiate(BMessage* archive); + + orientation Orientation(); + void Orientation(orientation orient); + +private: + orientation fOrient; +}; + +#endif // _DIVIDER_H diff --git a/libs/libinterface/Jamfile b/libs/libinterface/Jamfile new file mode 100644 index 0000000..0f784b3 --- /dev/null +++ b/libs/libinterface/Jamfile @@ -0,0 +1,12 @@ +SubDir TOP libs libinterface ; + +SubDirSysHdrs [ FDirName $(TOP) libs ] ; + +StaticLibrary libinterface.a : + BitmapMenuItem.cpp + BitmapUtils.cpp + BitmapView.cpp + Divider.cpp + NotifyingTextView.cpp + PictureView.cpp +; diff --git a/libs/libinterface/NotifyingTextView.cpp b/libs/libinterface/NotifyingTextView.cpp new file mode 100644 index 0000000..6e43a90 --- /dev/null +++ b/libs/libinterface/NotifyingTextView.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Copyright 2009, Michael Davidson. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Davidson, slaad@bong.com.au + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include "NotifyingTextView.h" + + +NotifyingTextView::NotifyingTextView(const char* name, uint32 flags) + : BTextView(name, flags), + fMessenger(NULL) +{ +} + + +NotifyingTextView::~NotifyingTextView() +{ + if (fMessenger != NULL) + delete fMessenger; +} + + +void +NotifyingTextView::SetTarget(const BHandler* handler) +{ + if (fMessenger != NULL) + delete fMessenger; + fMessenger = new BMessenger(handler); +} + + +BMessage* +NotifyingTextView::Message() const +{ + return fMessage; +} + + +void +NotifyingTextView::SetMessage(BMessage* msg) +{ + fMessage = msg; +} + + +void +NotifyingTextView::InsertText(const char* text, int32 length, int32 offset, + const text_run_array* runs) +{ + if ((fMessenger != NULL) && fMessenger->IsValid()) { + BMessage msg(*fMessage); + msg.AddPointer("source", this); + fMessenger->SendMessage(&msg); + } + + BTextView::InsertText(text, length, offset, runs); +} + + +void +NotifyingTextView::DeleteText(int32 start, int32 finish) +{ + if ((fMessenger != NULL) && fMessenger->IsValid()) { + BMessage msg(*fMessage); + msg.AddPointer("source", this); + fMessenger->SendMessage(&msg); + } + + BTextView::DeleteText(start, finish); +} diff --git a/libs/libinterface/NotifyingTextView.h b/libs/libinterface/NotifyingTextView.h new file mode 100644 index 0000000..a00f1b7 --- /dev/null +++ b/libs/libinterface/NotifyingTextView.h @@ -0,0 +1,36 @@ +/* + * Copyright 2009-2010, Pier Luigi Fiorini. All rights reserved. + * Copyright 2009, Michael Davidson. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _NOTIFYING_TEXT_VIEW_H +#define _NOTIFYING_TEXT_VIEW_H + +#include +#include +#include + +class BMessenger; + +class NotifyingTextView : public BTextView { +public: + NotifyingTextView(const char* name, uint32 flags + = B_WILL_DRAW | B_PULSE_NEEDED); + ~NotifyingTextView(); + + void SetTarget(const BHandler* handler); + + BMessage* Message() const; + void SetMessage(BMessage* msg); + +protected: + virtual void InsertText(const char* text, int32 length, int32 offset, + const text_run_array* runs = NULL); + virtual void DeleteText(int32 start, int32 finish); + +private: + BMessenger* fMessenger; + BMessage* fMessage; +}; + +#endif // _NOTIFYING_TEXT_VIEW_H diff --git a/libs/libinterface/PictureView.cpp b/libs/libinterface/PictureView.cpp new file mode 100644 index 0000000..92863e3 --- /dev/null +++ b/libs/libinterface/PictureView.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include + +#include "PictureView.h" + + +PictureView::PictureView(const char* name, const char* filename, uint32 flags) + : BView(name, flags), + fBitmap(NULL), + fWidth(0.0f), + fHeight(0.0f) +{ + // Set transparent + SetViewColor(B_TRANSPARENT_COLOR); + + // Try to get the image + fBitmap = BTranslationUtils::GetBitmap(filename); + + if (fBitmap) { + BRect frame(fBitmap->Bounds()); + + fWidth = frame.Width(); + fHeight = frame.Height(); + } else + return; + + ResizeTo(fWidth, fHeight); +} + + +PictureView::~PictureView() +{ + delete fBitmap; + fBitmap = NULL; +} + + +status_t +PictureView::InitCheck() +{ + if (fBitmap != NULL) + return B_OK; + return B_ERROR; +} + + +BSize +PictureView::MinSize() +{ + return BSize(fWidth, fHeight); +} + + +BSize +PictureView::MaxSize() +{ + return MinSize(); +} + + +BSize +PictureView::PreferredSize() +{ + return MinSize(); +} + + +void +PictureView::Draw(BRect frame) +{ + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + + if (fBitmap) + DrawBitmap(fBitmap, BPoint(0, 0)); +} diff --git a/libs/libinterface/PictureView.h b/libs/libinterface/PictureView.h new file mode 100644 index 0000000..a46cf65 --- /dev/null +++ b/libs/libinterface/PictureView.h @@ -0,0 +1,32 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PICTURE_VIEW_H +#define _PICTURE_VIEW_H + +#include + +class BBitmap; + +class PictureView : public BView { +public: + PictureView(const char* name, const char* filename, + uint32 flags = B_WILL_DRAW); + ~PictureView(); + + status_t InitCheck(); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + + virtual void Draw(BRect frame); + +private: + BBitmap* fBitmap; + float fWidth; + float fHeight; +}; + +#endif // _PICTURE_VIEW_H diff --git a/libs/libjabber/Base64.cpp b/libs/libjabber/Base64.cpp new file mode 100644 index 0000000..fe2ad78 --- /dev/null +++ b/libs/libjabber/Base64.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. + * Copyright 2004-2009, René Nyffenegge + * Distributed under the terms of the MIT License. + */ + +// Based on original code from: +// http://www.adp-gmbh.ch/cpp/common/base64.html + +#include + +#include "Base64.h" + +static const BString chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +Base64::Base64() +{ +} + + +BString +Base64::Encode(const uchar* data, size_t length) +{ + BString encoded; + int32 i = 0; + uchar array3[3], array4[4]; + + while (length--) { + array3[i++] = *(data++); + + if (i == 3) { + array4[0] = (uchar)((array3[0] & 0xfc) >> 2); + array4[1] = (uchar)(((array3[0] & 0x03) << 4) + ((array3[1] & 0xf0) >> 4)); + array4[2] = (uchar)(((array3[1] & 0x0f) << 2) + ((array3[2] & 0xc0) >> 6)); + array4[3] = (uchar)(((array4[2] & 0x3) << 6) + array4[3]); + + for (i = 0; i < 3; i++) + encoded += array3[i]; + i = 0; + } + } + + if (i) { + for (int32 j = i; j < 4; j++) + array4[j] = 0; + + for (int32 j = 0; j < 4; j++) + array4[j] = (uchar)chars.FindFirst(array4[j]); + + array3[0] = (uchar)((array4[0] << 2) + ((array4[i] & 0x30) >> 4)); + array3[1] = (uchar)(((array4[1] & 0xf) << 4) + ((array4[2] & 0x3c) >> 2)); + array3[2] = (uchar)(((array4[2] & 0x3) << 6) + array4[3]); + + for (int32 j = 0; j < i - 1; j++) + encoded += array3[j]; + } + + return encoded; +} + + +bool +Base64::IsBase64(uchar c) +{ + return isalnum(c) || (c == '+') || (c == '/'); +} + + +BString +Base64::Decode(const BString& data) +{ + int32 length = data.Length(); + int32 i = 0; + int32 index = 0; + uchar array4[4], array3[3]; + BString decoded; + + while (length-- && (data[index] != '=') && IsBase64(data[index])) { + array4[i++] = data[index]; + index++; + + if (i == 4) { + for (i = 0; i < 4; i++) + array4[i] = (uchar)chars.FindFirst(array4[i]); + + array3[0] = (uchar)((array4[0] << 2) + ((array4[1] & 0x30)>> 4)); + array3[1] = (uchar)(((array4[1] & 0xf) << 4) + ((array4[2] & 0x3c) >> 2)); + array3[2] = (uchar)(((array4[2] & 0x3) << 6) + array4[3]); + + for (i = 0; i < 3; i++) + decoded += array3[i]; + i = 0; + } + } + + if (i) { + int32 j; + + for (j = i; j < 4; j++) + array4[j] = 0; + + for (j = 0; j < 4; j++) + array4[j] = (uchar)chars.FindFirst(array4[j]); + + array3[0] = (uchar)((array4[0] << 2) + ((array4[1] & 0x30) >> 4)); + array3[1] = (uchar)(((array4[1] & 0xf) << 4) + ((array4[2] & 0x3c) >> 2)); + array3[2] = (uchar)(((array4[2] & 0x3) << 6) + array4[3]); + + for (j = 0; j < i - 1; j++) + decoded += array3[j]; + } + + return decoded; +} diff --git a/libs/libjabber/Base64.h b/libs/libjabber/Base64.h new file mode 100644 index 0000000..3188a05 --- /dev/null +++ b/libs/libjabber/Base64.h @@ -0,0 +1,21 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. + * Copyright 2004-2009, René Nyffenegge + * Distributed under the terms of the MIT License. + */ +#ifndef _BASE_64_H +#define _BASE_64_H + +#include + +class Base64 { +public: + static bool IsBase64(uchar c); + static BString Encode(const uchar* data, size_t length); + static BString Decode(const BString& data); + +private: + Base64(); +}; + +#endif // _BASE_64_H diff --git a/libs/libjabber/JabberAgent.cpp b/libs/libjabber/JabberAgent.cpp new file mode 100644 index 0000000..00e87a9 --- /dev/null +++ b/libs/libjabber/JabberAgent.cpp @@ -0,0 +1,134 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ + +#include + +#include "JabberAgent.h" +#include "Logger.h" + + +JabberAgent::JabberAgent() + : fGroupChat(false), + fSearchable(false), + fTransport(false), + fRegistration(false), + fService(""), + fName(""), + fJid("") +{ +} + + +JabberAgent::~JabberAgent() +{ +} + + +void +JabberAgent::PrintToStream() +{ + logmsg("JabberAgent:"); + logmsg(" Name: %s", fName.String()); + logmsg(" Service: %s", fService.String()); + logmsg(" Jid: %s", fJid.String()); +} + + +bool +JabberAgent::HasGroupChat() +{ + return fGroupChat; +} + + +bool +JabberAgent::IsTransport() +{ + return fTransport; +} + + +bool +JabberAgent::Searchable() +{ + return fSearchable; +} + + +bool +JabberAgent::AllowsRegistration() +{ + return fRegistration; +} + + +BString +JabberAgent::GetService() const +{ + return fService; +} + + +BString +JabberAgent::GetName() const +{ + return fName; +} + + +BString +JabberAgent::GetJid() const +{ + return fJid; +} + + +void +JabberAgent::SetService(const BString& service) +{ + fService = service; +} + + +void +JabberAgent::SetName(const BString& name) +{ + fName = name; +} + + +void +JabberAgent::SetJid(const BString& jid) +{ + fJid = jid; +} + + +void +JabberAgent::SetGroupChat(bool groupChat) +{ + fGroupChat = groupChat; +} + + +void +JabberAgent::SetSearchable(bool searchable) +{ + fSearchable = searchable; +} + + +void +JabberAgent::SetTransport(bool transport) +{ + fTransport = transport; +} + + +void +JabberAgent::SetRegistration(bool registration) +{ + fRegistration = registration; +} diff --git a/libs/libjabber/JabberAgent.h b/libs/libjabber/JabberAgent.h new file mode 100644 index 0000000..dca1e94 --- /dev/null +++ b/libs/libjabber/JabberAgent.h @@ -0,0 +1,45 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ +#ifndef _JABBER_AGENT_H +#define _JABBER_AGENT_H + +#include + +class JabberAgent { +public: + JabberAgent(); + ~JabberAgent(); + + void PrintToStream(); + + bool HasGroupChat(); + bool Searchable(); + bool IsTransport(); + bool AllowsRegistration(); + + BString GetService() const; + BString GetName() const; + BString GetJid() const; + BString GetInstructions() const; + + void SetGroupChat(bool groupChat); + void SetSearchable(bool searchable); + void SetTransport(bool transport); + void SetRegistration(bool registration); + void SetService(const BString& service); + void SetName(const BString& name); + void SetJid(const BString& jid); + +private: + bool fGroupChat; + bool fSearchable; + bool fTransport; + bool fRegistration; + BString fService; + BString fName; + BString fJid; +}; + +#endif // _JABBER_AGENT_H diff --git a/libs/libjabber/JabberContact.cpp b/libs/libjabber/JabberContact.cpp new file mode 100644 index 0000000..a4d6fad --- /dev/null +++ b/libs/libjabber/JabberContact.cpp @@ -0,0 +1,135 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ + +#include + +#include "JabberContact.h" +#include "Logger.h" + +JabberContact::JabberContact() + : fPresence(new JabberPresence()), + fId(""), fVCard(NULL) +{ +} + + +JabberContact::~JabberContact() +{ +} + + +void +JabberContact::PrintToStream() +{ + logmsg("JabberContact:"); + logmsg(" Name: %s", fName.String()); + logmsg(" Group: %s", fGroup.String()); + logmsg(" Jid: %s", fJid.String()); +} + + +void +JabberContact::SetName(const BString& name) +{ + fName = name; +} + + +void +JabberContact::SetGroup(const BString& group) +{ + fGroup = group; +} + + +void +JabberContact::SetPresence(JabberPresence* presence) +{ + fPresence = presence; +} + + +void +JabberContact::SetPresence() +{ + delete fPresence; + fPresence = new JabberPresence(); +} + + +void +JabberContact::SetJid(const BString& jid) +{ + fJid = jid; +} + + +void +JabberContact::SetVCard(JabberVCard* vCard) +{ + fVCard = vCard; +} + + +void +JabberContact::SetSubscription(const BString& subscription) +{ + fSubscription = subscription; +} + + +BString +JabberContact::GetSubscription() const +{ + return fSubscription; +} + + +BString +JabberContact::GetName() const +{ + return fName; +} + + +BString +JabberContact::GetGroup() const +{ + return fGroup; +} + +JabberPresence* +JabberContact::GetPresence() +{ + return fPresence; +} + + +BString +JabberContact::GetJid() const +{ + return fJid; +} + + +JabberVCard* +JabberContact::GetVCard() const +{ + return fVCard; +} + + +BString +JabberContact::GetLastMessageID() const +{ + return fId; +} + + +void +JabberContact::SetLastMessageID(const BString& id) +{ + fId = id; +} diff --git a/libs/libjabber/JabberContact.h b/libs/libjabber/JabberContact.h new file mode 100644 index 0000000..1faa0e4 --- /dev/null +++ b/libs/libjabber/JabberContact.h @@ -0,0 +1,46 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ +#ifndef _JABBER_CONTACT_H +#define _JABBER_CONTACT_H + +#include + +#include "JabberPresence.h" +#include "JabberVCard.h" + +class JabberContact { +public: + JabberContact(); + virtual ~JabberContact(); + + void SetName(const BString& name); + void SetGroup(const BString& group); + void SetSubscription(const BString& group); + virtual void SetPresence(); + virtual void SetPresence(JabberPresence* presence); + void SetJid(const BString& jid); + void SetVCard(JabberVCard* vCard); + void PrintToStream(); + BString GetName() const; + BString GetGroup() const; + BString GetSubscription() const; + JabberPresence* GetPresence(); + BString GetJid() const; + JabberVCard* GetVCard() const; + + BString GetLastMessageID() const; + void SetLastMessageID(const BString& id); + +private: + BString fJid; + BString fGroup; + JabberPresence* fPresence; + BString fName; + BString fId; + BString fSubscription; + JabberVCard* fVCard; +}; + +#endif // JABBER_CONTACT_H diff --git a/libs/libjabber/JabberElement.cpp b/libs/libjabber/JabberElement.cpp new file mode 100644 index 0000000..7d51224 --- /dev/null +++ b/libs/libjabber/JabberElement.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ + +#include + +#include "JabberElement.h" + +JabberElement::JabberElement() + : fName(""), + fData(""), + fAttr(NULL), + fAttrCount(-1) +{ +} + + +JabberElement::~JabberElement() +{ + Free(); +} + + +void +JabberElement::SetName(const BString& name) +{ + fName = name; +} + + +BString +JabberElement::GetName() const +{ + return fName; +} + + +void +JabberElement::SetData(const BString& data) +{ + fData = data; +} + + +BString +JabberElement::GetData() const +{ + return fData; +} + + +void +JabberElement::SetAttr(const char** attr) +{ + Free(); + if (attr) { + const char** a = attr; + + fAttrCount = 0; + + while (*a) { + fAttrCount++; + a++; + } + + fAttr = new char *[fAttrCount + 1]; + for (int32 i = 0; i < fAttrCount; i++) { + fAttr[i] = new char[strlen(attr[i]) + 1]; + strcpy(fAttr[i], attr[i]); + } + } +} + + +const char** +JabberElement::GetAttr() const +{ + return (const char **)fAttr; +} + + +int32 +JabberElement::GetAttrCount() const +{ + return fAttrCount; +} + + +void +JabberElement::Free() +{ + if (fAttrCount != -1) { + for (int32 i = 0; i < fAttrCount; i++) + delete [] fAttr[i]; + delete fAttr; + fAttr = NULL; + fAttrCount = -1; + } +} diff --git a/libs/libjabber/JabberElement.h b/libs/libjabber/JabberElement.h new file mode 100644 index 0000000..b1cd8cb --- /dev/null +++ b/libs/libjabber/JabberElement.h @@ -0,0 +1,35 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ +#ifndef _JABBER_ELEMENT_H +#define _JABBER_ELEMENT_H + +#include + +class JabberElement { +public: + JabberElement(); + ~JabberElement(); + + void SetName(const BString& name); + BString GetName() const; + + void SetData(const BString& data); + BString GetData() const; + + void SetAttr(const char** attr); + const char ** GetAttr() const; + + int32 GetAttrCount() const; + +private: + BString fName; + BString fData; + char ** fAttr; + int32 fAttrCount; + + void Free(); +}; + +#endif // _JABBER_ELEMENT_H diff --git a/libs/libjabber/JabberHandler.cpp b/libs/libjabber/JabberHandler.cpp new file mode 100644 index 0000000..bf77edd --- /dev/null +++ b/libs/libjabber/JabberHandler.cpp @@ -0,0 +1,1217 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrea Anzani, andrea.anzani@gmail.com + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include + +#include +#include +#include + +#include "JabberHandler.h" +#include "SHA1.h" +#include "States.h" +#include "Logger.h" +#include "VCardManager.h" + +JabberHandler::JabberHandler(const BString& name, JabberPlug* plug) + : fHost(""), + fUsername(""), + fJid(""), + fPassword(""), + fResource(""), + fPort(0), + fPriority(0), + fSocket(-1), + fAuthorized(false), + fPlug(plug), + fVCardManager(new VCardManager(this)), + fIncrementalId(666) //why not? +{ + fElementStack = new ElementList(20, true); + fNsStack = new StrList(); + fTypeStack = new StrList(); + fFromStack = new StrList(); + fRoster = new RosterList(20, true); + fAgents = new AgentList(20, true); + + fParser = XML_ParserCreate(NULL); + XML_SetUserData(fParser, this); + XML_SetElementHandler(fParser, StartElement, EndElement); + XML_SetCharacterDataHandler(fParser, Characters); +} + + +void +JabberHandler::Dispose() +{ + if (fParser) { + XML_ParserFree(fParser); + fParser = NULL; + } + + if (fElementStack) { + delete fElementStack; + fElementStack = NULL; + } + + if (fNsStack) { + delete fNsStack; + fNsStack = NULL; + } + + if (fTypeStack) { + delete fTypeStack; + fTypeStack = NULL; + } + + if (fFromStack) { + delete fFromStack; + fFromStack = NULL; + } + + if (fRoster) { + delete fRoster; + fRoster = NULL; + } + + if (fAgents) { + delete fAgents; + fAgents = NULL; + } +} + + +JabberHandler::~JabberHandler() +{ + Dispose(); +} + + +void +JabberHandler::UpdateJid() +{ + fJid = ""; + fJid << fUsername << "@" << fHost; +} + + +BString +JabberHandler::GetJid() const +{ + return fJid; +} + + +void +JabberHandler::SetHost(const BString & host) +{ + fHost = host; + UpdateJid(); +} + + +void +JabberHandler::SetUsername(const BString& username) +{ + fUsername = username; + UpdateJid(); +} + + +void +JabberHandler::SetPassword(const BString& password) +{ + fPassword = password; +} + + +void +JabberHandler::SetPort(int32 port) +{ + fPort = port; +} + + +void +JabberHandler::SetPriority(int32 priority) +{ + fPriority = priority; +} + + +void +JabberHandler::SetResource(const BString& resource) +{ + fResource = resource; +} + + +BString +JabberHandler::GetName() const +{ + return fUsername; +} + + +bool +JabberHandler::SendMessage(JabberMessage& message) +{ + BString body = message.GetBody(); + body.ReplaceAll("&", "&"); + body.ReplaceAll("<", "<"); + body.ReplaceAll(">", ">"); + body.ReplaceAll("\'", "'"); + body.ReplaceAll("\"", """); + + BString xml; + xml << "" << body << ""; + xml << ""; + xml << ""; + + Send(xml); + return true; +} + + +void +JabberHandler::SetOwnNickname(const BString& nick) +{ + // See http://xmpp.org/extensions/xep-0172.html, + // look at 4.5 nickname management + BString xml; + xml << ""; + xml << ""; + xml << ""; + xml << ""; + xml << nick << ""; + xml << ""; + Send(xml); +} + + +bool +JabberHandler::StartComposingMessage(JabberContact* contact) +{ + if (contact->GetLastMessageID().ICompare("") == 0) + return false; //?? no need to send notification + + // Send a composing event + BString xml; + xml << ""; + if (contact->GetLastMessageID() != "") + xml << "" << contact->GetLastMessageID() << ""; + xml << ""; + Send(xml); + + return true; +} + + +bool +JabberHandler::StopComposingMessage(JabberContact* contact) +{ + // Send a composing event + BString xml; + xml << ""; + xml << ""; + xml << ""; + Send(xml); + + return true; +} + + +void +JabberHandler::AddContact(const BString& name, const BString& jid, const BString& group) +{ + BString xml; + xml << ""; + xml << ""; + xml << "" << group << ""; + xml << ""; + xml << "I would like to add you to my roster."; + Send(xml); +} + + +void +JabberHandler::RemoveContact(const JabberContact* contact) +{ + BString xml; + xml << ""; + xml << " "; + xml << ""; + Send(xml); +} + + +void +JabberHandler::AcceptSubscription(const BString& jid) +{ + BString xml; + xml << ""; + Send(xml); +} + + +void +JabberHandler::SetStatus(int32 status, const BString& message) +{ + BString xml; + xml << ""; + break; + case S_OFFLINE: + xml << " type='unavailable'>"; + break; + case S_AWAY: + xml << ">away"; + break; + case S_XA: + xml << ">xa"; + break; + case S_DND: + xml << ">dnd"; + break; + case S_CHAT: + xml << ">chat"; + break; + default: + return; + } + + if (message != "") + xml << "" << message << ""; + + // Aha, fix the priority now as well :) + xml << "" << fPriority << ""; + + if (!fAuthorized) + LogOn(); + + Send(xml); + + if (status == S_OFFLINE) + LogOff(); +} + + +void +JabberHandler::LogOff() +{ + EndSession(); + fAuthorized = false; + Disconnected(""); +} + + + + +bool +JabberHandler::IsAuthorized() +{ + return fAuthorized; +} + + +void +JabberHandler::LogOn() +{ + if (fUsername != "" && fPassword != "" && fPort && fHost != "") { + // socket 0 is quite valid + if (fSocket < 0) + BeginSession(); + Authorize(); + } +} + + +void +JabberHandler::Register(JabberAgent* agent) +{ + BString xml; + xml << ""; + xml << ""; + xml << ""; + Send(xml); +} + + +void +JabberHandler::Register(JabberRegistration* registration) +{ + JabberRegistration::FieldList* fields = registration->GetFields(); + //const BList* fields = pRegistration->GetFields(); + + BString xml; + xml << ""; + xml << ""; + + JabberRegistration::FieldList::iterator i; + for (i = fields->begin(); i != fields->end(); i++) { + JabberRegistration::FieldPair pair = (*i); + if (pair.first != "" && pair.second != "") + xml << "<" << pair.first << ">" << pair.second << ""; + else if (pair.first != "") + xml << "<" << pair.first << "/>"; + } + xml << ""; + + Send(xml); + return; +} + + +int32 +JabberHandler::ReceivedData(const char* data, int32 length) +{ + if (length > 0) { + if (!XML_Parse(fParser, data, length, 0)) + logmsg("Parse failed!"); + } else { + if (IsAuthorized()) + Disconnected("Connection lost!"); + else + Disconnected(""); + + fAuthorized = false; + fSocket = -1; + CleanUpEnvirorment(); + } + return 0; +} + + +void +JabberHandler::Send(const BString& xml) +{ + if (fPlug->Send(xml) < 0) + Disconnected("Could not send"); +} + + +void +JabberHandler::Authorize() +{ + // http://xmpp.org/extensions/xep-0078.html + + CSHA1 sha1; + char shaPassword[256]; + + BString concatenad(fCurrentPresenceId); + concatenad << fPassword; + + sha1.Reset(); + sha1.Update((unsigned char*)concatenad.String(), concatenad.Length()); + sha1.Final(); + sha1.ReportHash(shaPassword, CSHA1::REPORT_HEX); + fLastAuthId << "auth" << fIncrementalId; + fIncrementalId++; + BString xml; + xml << ""; + xml << ""; + xml << "" << fUsername << ""; + xml << "" << fPassword << ""; + xml << "" << shaPassword << ""; // Error encoding the password?? + xml << "" << fResource << ""; + xml << ""; + xml << ""; + Send(xml); +} + + +bool +JabberHandler::BeginSession() +{ + BString xml; + + if (fUsername == "" || fHost == "" || fPassword == "" || fPort <= 0) + return false; + + fSocket = fPlug->StartConnection(fHost, fPort, this); + if (fSocket >= 0) { + xml << "\n"; + Send(xml); + return true; + } else { + logmsg("Failed to connect!"); + Disconnected("Failed to connect to host."); + return false; + } + + return false; +} + + +void +JabberHandler::EndSession() +{ + if (fSocket >= 0) { + BString xml; + xml << "\n"; + Send(xml); + } + CleanUpEnvirorment(); +} + +void +JabberHandler::CleanUpEnvirorment() +{ + XML_ParserFree(fParser); + + fElementStack->MakeEmpty(); + fNsStack->clear(); + fTypeStack->clear(); + fFromStack->clear(); + fRoster->MakeEmpty(); + fAgents->MakeEmpty(); + + fParser = XML_ParserCreate(NULL); + XML_SetUserData(fParser, this); + XML_SetElementHandler(fParser, StartElement, EndElement); + XML_SetCharacterDataHandler(fParser, Characters); +} + + +void +JabberHandler::StartElement(void* pUserData, const char* pName, const char** pAttr) +{ + BString name(pName); + JabberHandler* handler = reinterpret_cast(pUserData); + + // Authorize in the beginning of the stream + if (name.ICompare("stream:stream") == 0) { + const char* currentId = handler->HasAttribute("id", pAttr); + handler->fCurrentPresenceId = BString(currentId); + return; + } + + if (name.ICompare("iq") == 0) { + const char* type = handler->HasAttribute("type", pAttr); + const char* id = handler->HasAttribute("id", pAttr); + const char* from = handler->HasAttribute("from", pAttr); + + if (type != NULL && id != NULL) { + if (strcmp(type, "result") == 0) { + if (handler->fLastAuthId.Compare(id) == 0) { + handler->fAuthorized = true; + handler->Authorized(); + } + } else if (strcmp(type, "error") == 0) { + if (handler->fLastAuthId.Compare(id) == 0) { + handler->fAuthorized = false; + handler->fSocket = -1; + handler->Disconnected("Error logging in!"); + } + } + + // Always save from and type attributes + handler->fFromStack->push_back(BString(from)); + handler->fTypeStack->push_back(BString(type)); + } + } + + JabberElement* element = new JabberElement(); + element->SetName(pName); + element->SetAttr(pAttr); + handler->fElementStack->AddItem(element); + + if (name.ICompare("query") == 0) { + const char* ns = handler->HasAttribute("xmlns", pAttr, element->GetAttrCount()); + if (ns) + handler->fNsStack->push_back(BString(ns)); + } +} + + +void +JabberHandler::EndElement(void* pUserData, const char* pName) +{ + BString name(pName); + JabberHandler* handler = (JabberHandler *)pUserData; + + JabberElement* element = handler->fElementStack->LastItem(); + if (element && element->GetName().ICompare("new_data") == 0) + element->SetName("data"); + + if (name.ICompare("message") == 0) { + JabberMessage* message = handler->BuildMessage(); + handler->Message(message); + } else if (name.ICompare("presence") == 0) { + JabberPresence* presence = handler->BuildPresence(); + + if (presence->GetType().ICompare("subscribe") == 0) + handler->SubscriptionRequest(presence); + else if (presence->GetType().ICompare("unsubscribe") == 0) + handler->Unsubscribe(presence); + else { + handler->Presence(presence); + handler->UpdateRoster(presence); + } + } else if (name.ICompare("query") == 0) { + if (handler->fNsStack->size() != 0) { + BString obj = *(handler->fNsStack->begin()); + handler->fNsStack->pop_front(); // removes first item + + if (!obj.ICompare("jabber:iq:roster")) { + handler->BuildRoster(); + handler->Roster(handler->fRoster); + } else if (!obj.ICompare("jabber:iq:version")) { + handler->SendVersion(); + } else if (!obj.ICompare("jabber:iq:agents")) { + handler->BuildAgents(); + handler->Agents(handler->fAgents); + } else if (!obj.ICompare("jabber:iq:register")) { + JabberRegistration * r = handler->BuildRegistration(); + handler->Registration(r); + delete r; + } + } + } else if (name.ICompare("vCard") == 0) { + BString type; + if (handler->fTypeStack->size() != 0) + type = *(handler->fTypeStack->begin()); + + BString from; + if (handler->fFromStack->size() != 0) + from = *(handler->fFromStack->begin()); + + if (type.ICompare("result") == 0) { + from.ToLower(); + JabberVCard* vCard = handler->BuildVCard(from); + + for (int32 i = 0; i < handler->fRoster->CountItems(); i++) { + JabberContact* contact = handler->fRoster->ItemAt(i); + if (contact->GetJid().ICompare(from) == 0) { + contact->SetVCard(vCard); + handler->fVCardManager->VCardReceived(contact); + } + } + + //support also receiving our own vCard + if (handler->GetJid().ICompare(from) == 0) { + // maybe we should also create an instance of JabberContact that represent 'me' + JabberContact contact; + contact.SetJid(handler->GetJid()); + contact.SetName(vCard->GetFullName()); + contact.SetVCard(vCard); + handler->fVCardManager->VCardReceived(&contact); + handler->OwnContactInfo(&contact); + + } + } + } else if (name.ICompare("iq") == 0) { + // Remove last type and from attributes from their stacks + if (handler->fTypeStack->size() != 0) + handler->fTypeStack->pop_front(); + if (handler->fFromStack->size() != 0) + handler->fFromStack->pop_front(); + } +} + + +void +JabberHandler::Characters(void* pUserData, const char* pString, int pLen) +{ + JabberHandler* handler = (JabberHandler *)pUserData; + JabberElement* element = handler->fElementStack->LastItem(); + + char tmpz[pLen + 1]; + memcpy(tmpz, pString, pLen); + tmpz[pLen] = 0; + + if (!element || element->GetName().ICompare("new_data") != 0) { + if (pLen == 1 && (pString[0] == '\n' || pString[0] == 9 || pString[0] == 32)) + return; + element = new JabberElement(); + element->SetName("new_data"); + element->SetData(tmpz); + handler->fElementStack->AddItem(element); + } else if (element->GetName().ICompare("new_data") == 0) { + BString tmp; + tmp << element->GetData().String() << tmpz ; + element->SetData(tmp.String()); + } +} + + +/************************************************ + * Builds a message from the element stack + ************************************************/ +JabberMessage* +JabberHandler::BuildMessage() +{ + // http://xmpp.org/extensions/xep-0184.html + JabberMessage* message = new JabberMessage(); + JabberElement* element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + JabberElement* previous = NULL; + StrList data; + + while (element->GetName().ICompare("message") != 0) { + if (element->GetName().ICompare("body") == 0) { + if (previous != 0 && previous->GetName().ICompare("data") == 0) + message->SetBody(previous->GetData()); + } else if (element->GetName().ICompare("error") == 0) { + if (previous != 0 && previous->GetName().ICompare("data") == 0) + message->SetError(previous->GetData()); + } else if (element->GetName().ICompare("x") == 0) { + BString xmlns(HasAttribute("xmlns", element->GetAttr(), + element->GetAttrCount())); + message->SetX(xmlns); + + if (previous != 0) { + if (previous->GetName().ICompare("composing") == 0) + message->SetX("composing"); + else { + // old olmeki compatibily.. + if (previous->GetName().ICompare("data") == 0) { + if (previous->GetData().ICompare("Offline Storage") == 0) + message->SetOffline(true); + } + } + } + } + + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + BString from(HasAttribute("from", + element->GetAttr(),element->GetAttrCount())); + message->SetID(HasAttribute("id", + element->GetAttr(),element->GetAttrCount())); + message->SetType(HasAttribute("type", + element->GetAttr(),element->GetAttrCount())); + + from.ToLower(); //xeD: jid always low case to avoid confusion. + StripResource(from); + message->SetFrom(from); + message->SetTo(GetJid()); + if (message->GetStamp() == "") + TimeStamp(*message); + + delete previous; + delete element; + + return message; +} + +/************************************************************ + * Builds and/or updates the roster from elements on stack + ************************************************************/ +JabberHandler::RosterList * +JabberHandler::BuildRoster() +{ + // http://xmpp.org/extensions/xep-0147.html#actions-roster + JabberContact* contact = NULL; + JabberElement* element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + JabberElement* previous = NULL; + + while (element->GetName().ICompare("query") != 0) { + contact = new JabberContact(); + while (element->GetName().ICompare("item") != 0) { + if (element->GetName().ICompare("group") == 0 && previous && + previous->GetName().ICompare("data") == 0) + contact->SetGroup(previous->GetData()); + + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + BString jid(HasAttribute("jid", element->GetAttr(),element->GetAttrCount())); + StripResource(jid); + jid.ToLower(); //xeD: jid always low case to avoid confusion. + contact->SetJid(jid); + contact->SetSubscription(HasAttribute("subscription", element->GetAttr(),element->GetAttrCount())); + + const char * tmpValue; + tmpValue = HasAttribute("name", element->GetAttr(),element->GetAttrCount()); + tmpValue != NULL ? contact->SetName(tmpValue) : contact->SetName(contact->GetJid()); + + if (contact->GetGroup() == NULL) { + const JabberAgent * agent = IsAgent(contact->GetJid()); + if (agent) { + contact->SetGroup("Transports"); + contact->SetName(agent->GetName()); + } else if (contact->GetSubscription() == "" || + contact->GetSubscription().ICompare("from") == 0) + contact->SetGroup("Unsubscribed"); + else + contact->SetGroup("Unsorted"); + } + + UpdateRoster(contact); + + if (previous) + delete previous; + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + delete element; + delete previous; + + return fRoster; +} + +/****************************************************************** + * Builds a nice little precense object from the elements on stack + ******************************************************************/ +JabberPresence* +JabberHandler::BuildPresence() +{ + // http://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2 + JabberElement* element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + JabberElement* previous = 0; + JabberPresence* presence = new JabberPresence(); + + presence->SetShow(S_ONLINE); + while (element->GetName().ICompare("presence") != 0) { + if (element->GetName().ICompare("show") == 0) { + if (previous != NULL && previous->GetName().ICompare("data") == 0) + presence->SetShowFromString(previous->GetData()); + } else if (element->GetName().ICompare("status") == 0) { + if (previous != NULL && previous->GetName().ICompare("data") == 0) + presence->SetStatus(previous->GetData()); + } else if (element->GetName().ICompare("photo") == 0) { + if (previous != NULL && previous->GetName().ICompare("data") == 0) + presence->SetPhotoSHA1(previous->GetData()); + } + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + BString from(HasAttribute("from", + element->GetAttr(),element->GetAttrCount())); + from.ToLower(); //xeD: jid always low case to avoid confusion. + presence->ParseFrom(from); + presence->SetType(HasAttribute("type", + element->GetAttr(),element->GetAttrCount())); + + fVCardManager->RefinePresence(presence); + + delete previous; + delete element; + + return presence; +} + +/****************************************************************** + * Builds a list of available agents on the server, this is called + * as a respond to the RequestAgents() + *****************************************************************/ +JabberHandler::AgentList* +JabberHandler::BuildAgents() +{ + // http://xmpp.org/extensions/xep-0094.html + JabberAgent* agent; + JabberElement* element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + JabberElement* previous = NULL; + + while (element->GetName().ICompare("query") != 0) { + agent = new JabberAgent(); + while (element->GetName().ICompare("agent") != 0) { + if (element->GetName().ICompare("service") == 0 && + previous->GetName().ICompare("data") == 0) + agent->SetService(previous->GetData()); + + if (element->GetName().ICompare("name") == 0 && + previous->GetName().ICompare("data") == 0) + agent->SetName(previous->GetData()); + + if (element->GetName().ICompare("groupchat")) + agent->SetGroupChat(true); + + if (element->GetName().ICompare("search")) + agent->SetSearchable(true); + + if (element->GetName().ICompare("transport")) + agent->SetTransport(true); + + if (element->GetName().ICompare("register")) + agent->SetRegistration(true); + + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + BString jid(HasAttribute("jid", element->GetAttr(), element->GetAttrCount())); + jid.ToLower(); //xeD: jid always low case to avoid confusion. + agent->SetJid(jid); + + fAgents->AddItem(agent); + + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + delete element; + delete previous; + + return fAgents; +} + +/********************************************************* + * Builds a JabberRegistration object from elements on the + * element stack + *********************************************************/ +JabberRegistration* +JabberHandler::BuildRegistration() +{ + // http://xmpp.org/extensions/xep-0077.html + JabberElement* element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + JabberElement* previous = NULL; + JabberRegistration* registration = new JabberRegistration(); + + while (element->GetName().ICompare("query") != 0) { + if (element->GetName().ICompare("instructions") == 0) { + if (previous != NULL && previous->GetName().ICompare("data") == 0) + registration->SetInstructions(previous->GetData()); + } else if(element->GetName().ICompare("data") != 0) { + if (previous != NULL && previous->GetName().ICompare("data") == 0) + registration->SetFieldValue(element->GetName().String(), + previous->GetData().String(), true); + else + registration->AddField(element->GetName(), ""); // no value + } + + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + delete element; + + // TODO: what if CountItems() == 0? :) This applies to all uses of CountItems() + // It will crash RemoveItem() (passing a -1) + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + BString jid(HasAttribute("from", element->GetAttr())); + jid.ToLower(); //xeD: jid always low case to avoid confusion. + registration->SetJid(jid); + + delete previous; + delete element; + + return registration; +} + + +/********************************************************* + * Builds a JabberRegistration object from elements on the + * element stack + *********************************************************/ +JabberVCard* +JabberHandler::BuildVCard(const BString& from) +{ + // http://xmpp.org/extensions/xep-0054.html#sect-id2251780 + JabberVCard* vCard = new JabberVCard(); + JabberElement* element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + JabberElement* previous = NULL; + + while (element->GetName().ICompare("vCard") != 0) { + if (element->GetName().ICompare("FN") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetFullName(previous->GetData()); + } else if (element->GetName().ICompare("GIVEN") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetGivenName(previous->GetData()); + } else if (element->GetName().ICompare("FAMILY") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetFamilyName(previous->GetData()); + } else if (element->GetName().ICompare("MIDDLE") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetMiddleName(previous->GetData()); + } else if (element->GetName().ICompare("NICKNAME") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetNickname(previous->GetData()); + } else if (element->GetName().ICompare("EMAIL") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetEmail(previous->GetData()); + } else if (element->GetName().ICompare("URL") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetURL(previous->GetData()); + } else if (element->GetName().ICompare("BDAY") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetBirthday(previous->GetData()); + } else { + // Handle PHOTO childs + if (element->GetName().ICompare("EXTVAL") == 0) { + // Got a URI to an external content + // TODO: + } else { + if (element->GetName().ICompare("TYPE") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetPhotoMimeType(previous->GetData()); + } else if (element->GetName().ICompare("BINVAL") == 0) { + if (previous && previous->GetName().ICompare("data") == 0) + vCard->SetPhotoContent(previous->GetData()); + } + } + } + + if (previous) + delete previous; + + previous = element; + element = fElementStack->RemoveItemAt(fElementStack->CountItems() - 1); + } + + vCard->ParseFrom(from); + logmsg("got vcard from %s: %s", from.String(), vCard->GetFullName().String()); + + + delete previous; + delete element; + + return vCard; +} + + +void +JabberHandler::SendVersion() +{ +} + + +void +JabberHandler::RequestRoster() +{ + BString xml; + xml << ""; + Send(xml); +} + + +void +JabberHandler::RequestAgents() +{ + BString xml; + xml << ""; + xml << ""; + xml << ""; + Send(xml); +} + + +void +JabberHandler::RequestSelfVCard() +{ + // http://xmpp.org/extensions/xep-0054.html#sect-id2251582 + // TODO +} + +void +JabberHandler::RequestVCard(const BString & jid) +{ + // http://xmpp.org/extensions/xep-0054.html#sect-id2251780 + BString xml; + xml << ""; + Send(xml); +} + + +void +JabberHandler::RequestVCard(JabberContact* contact) +{ + // Ignore NULL contact + if (!contact) + return; + + RequestVCard(contact->GetJid()); +} + + +void +JabberHandler::UpdateRoster(JabberPresence* presence) +{ + // filter out from roster ourself + if (presence->GetJid().Compare(GetJid()) == 0) + return; + + JabberContact* contact; + int size = fRoster->CountItems(); + + for (int i = 0; i < size; i++) { + contact = fRoster->ItemAt(i); + + if (presence->GetJid().ICompare(contact->GetJid()) == 0) { + contact->SetPresence(presence); + return; + } + } + + contact = new JabberContact(); + contact->SetJid(presence->GetJid()); + contact->SetName(presence->GetJid()); + contact->SetPresence(presence); + fRoster->AddItem(contact); + //xeD: commeting this: RequestVCard(contact); +} + + +void +JabberHandler::UpdateRoster(JabberContact* contact) +{ + // filter out from roster ourself + if (contact->GetJid().Compare(GetJid()) == 0) + return; + + JabberContact* current; + int size = fRoster->CountItems(); + + for (int i = 0; i < size; i++) { + current = fRoster->ItemAt(i); + + if (contact->GetJid().ICompare(current->GetJid()) == 0) { + current->SetName(contact->GetName()); + current->SetGroup(contact->GetGroup()); + + if (contact->GetSubscription() == "remove") { + fRoster->RemoveItem(current); + //delete current; + delete contact; + return; + } else if (contact->GetSubscription() != "") + current->SetSubscription(contact->GetSubscription()); + + delete contact; + return; + } + } + + fRoster->AddItem(contact); + //xeD: commeting this: RequestVCard(contact); +} + + +/********************* + * Utility methods + *********************/ +const JabberAgent* +JabberHandler::IsAgent(const BString& jid) +{ + JabberAgent* agent; + int32 nbrAgents = fAgents->CountItems(); + + for (int32 i = 0; i < nbrAgents; i++) { + agent = fAgents->ItemAt(i); + if (jid.ICompare(agent->GetJid()) == 0) + return agent; + } + + return NULL; +} + + +void +JabberHandler::TimeStamp(JabberMessage& message) +{ + BString tmp; + BString timeString; + + time_t currentTime = time(NULL); + struct tm * t = localtime(¤tTime); + + timeString << (t->tm_year + 1900); + TwoDigit(t->tm_mon, timeString); + TwoDigit(t->tm_mday, timeString); + timeString << "T"; + TwoDigit(t->tm_hour, timeString); + timeString << ":"; + TwoDigit(t->tm_min, timeString); + timeString << ":"; + TwoDigit(t->tm_sec, timeString); + + message.SetStamp(timeString); +} + + +BString +JabberHandler::TwoDigit(int32 number, BString& string) +{ + if(number < 10) + string << "0" << number; + else + string << number; + + return string; +} + + +const char* +JabberHandler::HasAttribute(const char* pName, const char** pAttributes, int32 count) +{ + for (int32 i = 0; i < count; i += 2) { + if (strcmp(pAttributes[i], pName) == 0) + return pAttributes[i + 1]; + } + + return NULL; +} + + +const char * +JabberHandler::HasAttribute(const char* pName, const char** pAttributes) +{ + for (int32 i = 0; pAttributes[i]; i += 2) { + if (strcmp(pAttributes[i], pName) == 0) + return pAttributes[i + 1]; + } + + return NULL; +} + + +void +JabberHandler::StripResource(BString& jid) +{ + int i = jid.FindFirst('/'); + if (i != -1) + jid.Remove(i, jid.Length() - i); +} + + +/*********************************** + * Callbacks + ***********************************/ + + +void +JabberHandler::Authorized() +{ + /* + * Important that we get the list of agents first so that we + * can add agents in the roster to a certain group + */ + RequestAgents(); + RequestRoster(); +} diff --git a/libs/libjabber/JabberHandler.h b/libs/libjabber/JabberHandler.h new file mode 100644 index 0000000..82101dc --- /dev/null +++ b/libs/libjabber/JabberHandler.h @@ -0,0 +1,171 @@ +/* + * Copyright 2002, The Olmeki Team. + * Distributed under the terms of the Olmeki License. + */ + +#ifndef _JABBER_HANDLER_H +#define _JABBER_HANDLER_H + +#include + +#include + +#include "ObjectList.h" + +#include + +#include "JabberAgent.h" +#include "JabberContact.h" +#include "JabberElement.h" +#include "JabberMessage.h" +#include "JabberPresence.h" +#include "JabberRegistration.h" +#include "JabberVCard.h" +#include "JabberPlug.h" + +class VCardManager; + +class JabberHandler { +public: + JabberHandler(const BString & name, JabberPlug*); + virtual ~JabberHandler(); + void Dispose(); + void LogOn(); + void LogOff(); + + //void Register(); + void Register(JabberRegistration * registration); + void Register(JabberAgent * agent); + + BString GetName() const; + + void SetHost(const BString & host); + void SetUsername(const BString & username); + void SetPassword(const BString & password); + void SetPort(int32 port); + void SetPriority(int32 priority); + void SetResource(const BString & resource); + + void UpdateJid(); + BString GetJid() const; + + bool IsAuthorized(); + void RemoveContact(const JabberContact * contact); + + int32 ReceivedData(const char *,int32); + +protected: + typedef BObjectList ElementList; + typedef std::list StrList; + typedef BObjectList RosterList; + typedef BObjectList AgentList; + + bool SendMessage(JabberMessage & message); + + void SetOwnNickname(const BString& nick); + + bool StartComposingMessage(JabberContact * contact); + bool StopComposingMessage(JabberContact * contact); + + void SetStatus(int32 status, const BString & message); + + void TimeStamp(JabberMessage & message); + + void AddContact(const BString & name, const BString & jid, const BString & group); + void AcceptSubscription(const BString & jid); + void UpdateRoster(JabberPresence * presence); + + // The JabberHandler takes ownership of the contact + void UpdateRoster(JabberContact * contact); + // by xeD + RosterList* getRosterList(){ return fRoster; }; + + //Callbacks + virtual void Authorized(); + virtual void Message(JabberMessage * message)=0; + virtual void Presence(JabberPresence * presence) =0; + virtual void Roster(RosterList * roster) =0; + virtual void Agents(AgentList * agents) =0; + virtual void Disconnected(const BString & reason) = 0; + virtual void SubscriptionRequest(JabberPresence * presence) = 0; + virtual void Registration(JabberRegistration * registration) = 0; + virtual void Unsubscribe(JabberPresence * presence) = 0; + virtual void OwnContactInfo(JabberContact* contact) = 0; +protected: +friend class VCardManager; + virtual void GotBuddyPhoto(const BString & jid, const BString & imagePath) = 0; + +private: + enum ID { + AUTH = 0, + ROSTER = 2 + }; + + BString fHost; + BString fUsername; + BString fJid; + BString fPassword; + int32 fPort; + BString fResource; + int32 fPriority; + + ElementList* fElementStack; + StrList* fNsStack; + StrList* fTypeStack; + StrList* fFromStack; + RosterList* fRoster; + AgentList* fAgents; + + int32 fSocket; + JabberPlug* fPlug; + + XML_Parser fParser; + bool fAuthorized; + + VCardManager* fVCardManager; + + BString fCurrentPresenceId; + BString fLastAuthId; + int32 fIncrementalId; + +//protected: +public: +//friend class VCardManager; + void RequestVCard(const BString & jid); + +protected: + void Send(const BString & xml); + void Authorize(); + bool BeginSession(); + void EndSession(); + void SendVersion(); + void RequestRoster(); + void RequestAgents(); + void RequestSelfVCard(); + void RequestVCard(JabberContact* contact); + + JabberMessage* BuildMessage(); + JabberPresence* BuildPresence(); + RosterList * BuildRoster(); + AgentList * BuildAgents(); + JabberRegistration* BuildRegistration(); + JabberVCard* BuildVCard(const BString& from); + + //int32 GetConnection(); + const JabberAgent* IsAgent(const BString & jid); + const char* HasAttribute(const char* name, const char** attributes, int32 count); + const char* HasAttribute(const char* name, const char** attributes); + + void StripResource(BString & jid); + BString TwoDigit(int32, BString &); + + static void StartElement(void* pUserData, const char* pName, const char** pAttr); + static void EndElement(void* pUserData, const char* pName); + static void Characters(void* pUserData, const char* pString, int pLen); + +private: + void CleanUpEnvirorment(); + +}; + +#endif // _JABBER_HANDLER_H diff --git a/libs/libjabber/JabberManager.h b/libs/libjabber/JabberManager.h new file mode 100644 index 0000000..691343a --- /dev/null +++ b/libs/libjabber/JabberManager.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef Jabber_MANAGER_H +#define Jabber_MANAGER_H + +#include +#include + +#include "CayaConstants.h" + +/** + +*/ + +class JabberManager +{ + public: + // who can be NULL if it's a general message + virtual void Error( const char * message, const char * who )=0; + + virtual void GotMessage( const char * from, const char * msg )=0; + virtual void MessageSent( const char * to, const char * msg )=0; + + virtual void LoggedIn()=0; + virtual void SetAway(bool)=0; + virtual void LoggedOut()=0; + + //virtual void GotBuddyList( list & )=0; + virtual void BuddyStatusChanged( const char * who, CayaStatus status )=0; +}; + +#endif diff --git a/libs/libjabber/JabberMessage.cpp b/libs/libjabber/JabberMessage.cpp new file mode 100644 index 0000000..6c2e110 --- /dev/null +++ b/libs/libjabber/JabberMessage.cpp @@ -0,0 +1,124 @@ +#include "JabberMessage.h" +#include "Logger.h" + +JabberMessage::JabberMessage() +{ + fTo = ""; + fFrom = ""; + fBody = ""; + fStamp = ""; + fId = ""; + fOffline= false; + fType=""; + fError=""; + fX=""; +} + +JabberMessage::JabberMessage(const JabberMessage & copy) +{ + fTo = copy.fTo; + fFrom = copy.fFrom; + fBody = copy.fBody; + fStamp = copy.fStamp; + fOffline= copy.fOffline; + fId = copy.fId; + fType=copy.fType; + fError=copy.fError; + fX=copy.fX; +} + +void +JabberMessage::PrintToStream() +{ + logmsg(" ** JabberMessage **"); + logmsg(" To: %s",fTo.String()); + logmsg(" Id: %s",fId.String()); + logmsg(" From: %s",fFrom.String()); + logmsg(" Body: %s",fBody.String()); + logmsg(" Stamp: %s",fStamp.String()); + logmsg(" Type: %s",fType.String()); + logmsg(" Error: %s",fError.String()); + logmsg(" X: %s",fX.String()); +} + + +JabberMessage::~JabberMessage() +{ +} + +void +JabberMessage::operator=(const JabberMessage & copy) +{ + fTo = copy.fTo; + fFrom = copy.fFrom; + fBody = copy.fBody; + fStamp = copy.fStamp; + fOffline= copy.fOffline; + fId = copy.fId; + fType=copy.fType; + fError=copy.fError; + fX=copy.fX; +} + +BString +JabberMessage::GetFrom() const +{ + return fFrom; +} + +BString +JabberMessage::GetTo() const +{ + return fTo; +} + +BString +JabberMessage::GetBody() const +{ + return fBody; +} + +BString +JabberMessage::GetStamp() const +{ + return fStamp; +} + +BString +JabberMessage::GetID() const +{ + return fId; +} +void +JabberMessage::SetFrom(const BString & from) +{ + fFrom = from; +} + +void +JabberMessage::SetTo(const BString & to) +{ + fTo = to; +} + +void +JabberMessage::SetBody(const BString & body) +{ + fBody = body; +} + +void +JabberMessage::SetStamp(const BString & stamp) +{ + fStamp = stamp; +} +void +JabberMessage::SetID(const BString & id) +{ + fId = id; +} +void +JabberMessage::SetOffline(const bool b) +{ + fOffline = b; +} diff --git a/libs/libjabber/JabberMessage.h b/libs/libjabber/JabberMessage.h new file mode 100644 index 0000000..f580e3d --- /dev/null +++ b/libs/libjabber/JabberMessage.h @@ -0,0 +1,48 @@ +#ifndef JABBER_MESSAGE_H +#define JABBER_MESSAGE_H + +#include + +class JabberMessage +{ +public: + JabberMessage(); + JabberMessage(const JabberMessage &); + ~JabberMessage(); + + void operator=(const JabberMessage &); + + BString GetFrom() const; + BString GetTo() const; + BString GetBody() const; + BString GetStamp() const; + BString GetID() const; + BString GetType() const { return fType; }; //by xeD + BString GetError() const { return fError; }; //by xeD + bool GetOffline() const { return fOffline; } + BString GetX(){ return fX;} + + void SetType(const BString & type){ fType=type; } //by xeD; + void SetError(const BString & err){ fError=err; } //by xeD; + void SetFrom(const BString & from); + void SetTo(const BString & from); + void SetBody(const BString & body); + void SetStamp(const BString & stamp); + void SetID(const BString & id); + void SetOffline(const bool b); + void SetX(const BString & x){ fX=x; } + void PrintToStream(); +private: + BString fFrom; + BString fTo; + BString fBody; + BString fStamp; + BString fId; // by xeD + BString fType; // by xeD (chat,error,..) + BString fError; // error message incluided? + BString fX; // ? FIX! + bool fOffline; +}; + + +#endif diff --git a/libs/libjabber/JabberPlug.h b/libs/libjabber/JabberPlug.h new file mode 100644 index 0000000..2718a37 --- /dev/null +++ b/libs/libjabber/JabberPlug.h @@ -0,0 +1,25 @@ +/* + Interface for a highlivel connection class + - basic implementations: + JabberSSLPlug (new code used by GoogleTalk) + JabberSocketPLug (old code BONE/net_server) + + 22 sept. 2005 by Andrea Anzani (andrea@tenar.it) +*/ +#ifndef JabberPlug_H_ +#define JabberPlug_H_ +#include + +class JabberPlug { + + public: + virtual ~JabberPlug() {}; + //private: + + virtual int StartConnection(BString fHost, int32 fPort,void*) = 0;//if >= 0 it's ok. + virtual int Send(const BString & xml) = 0; //if >= 0 it's ok. + virtual int StopConnection() = 0; +}; + +#endif +//. diff --git a/libs/libjabber/JabberPresence.cpp b/libs/libjabber/JabberPresence.cpp new file mode 100644 index 0000000..df52075 --- /dev/null +++ b/libs/libjabber/JabberPresence.cpp @@ -0,0 +1,179 @@ +#include "JabberPresence.h" +#include "States.h" +#include "Logger.h" + +JabberPresence::JabberPresence() +{ + fStatus = ""; + fJid = ""; + fType = ""; + fShow = S_OFFLINE; + fResource = ""; +} +void +JabberPresence::PrintToStream() +{ + logmsg("\nJabberPresence"); + logmsg(" Status: %s",fStatus.String()); + logmsg(" Show: %ld",fShow); + logmsg(" Jid: %s",fJid.String()); + +} +JabberPresence::JabberPresence(const JabberPresence & copy) +{ + SetStatus(copy.GetStatus()); + SetJid(copy.GetJid()); + SetType(copy.GetType()); + SetResource(copy.GetResource()); + fShow = copy.GetShow(); +} + +JabberPresence::~JabberPresence() +{ +} + +void +JabberPresence::operator=(const JabberPresence & rhs) +{ + if (this == &rhs) + return; + + SetStatus(rhs.GetStatus()); + SetJid(rhs.GetJid()); + SetType(rhs.GetType()); + SetResource(rhs.GetResource()); + fShow = rhs.fShow; +} + +int32 +JabberPresence::GetShow() const +{ + return fShow; +} + +BString +JabberPresence::GetType() const +{ + return fType; +} + +BString +JabberPresence::GetStatus() const +{ + return fStatus; +} + +BString +JabberPresence::GetJid() const +{ + return fJid; +} + +BString +JabberPresence::GetResource() const +{ + return fResource; +} + +void +JabberPresence::SetShowFromString(const BString & show) +{ + if (show != "") + { + if (!show.ICompare("xa")) + fShow = S_XA; + else if (!show.ICompare("away")) + fShow = S_AWAY; + else if (!show.ICompare("dnd")) + fShow = S_DND; + else if (!show.ICompare("chat")) + fShow = S_CHAT; + } +} + +void +JabberPresence::SetShow(int32 show) +{ + switch(show) + { + case S_XA: + fShow = S_XA; + break; + case S_AWAY: + fShow = S_AWAY; + break; + case S_ONLINE: + fShow = S_ONLINE; + break; + default: + fShow = S_OFFLINE; + } +} + +void +JabberPresence::SetType(const BString & type) +{ + fType = type; + if(fType.ICompare("unavailable") == 0) + SetShow(S_OFFLINE); +} + +void +JabberPresence::SetStatus(const BString & status) +{ + fStatus = status; +} + +void +JabberPresence::SetJid(const BString & jid) +{ + fJid = jid; +} + +void +JabberPresence::SetResource(const BString & resource) +{ + fResource = resource; +} + +void +JabberPresence::ParseFrom(const BString & from) +{ + fJid = ""; + fResource = ""; + + int32 i = from.FindFirst('/'); + if (i != -1) + { + from.CopyInto(fJid, 0, i); + from.CopyInto(fResource, i + 1, from.Length()); + } + else + { + fJid = from; + } +} + +BString +JabberPresence::GetPhotoSHA1() const +{ + return fPhotoSHA1; +} + +BString +JabberPresence::GetPhotoPath() const +{ + return fPhotoPath; +} + +void +JabberPresence::SetPhotoSHA1(const BString & sha1) +{ + fPhotoSHA1 = sha1; +} + +void +JabberPresence::SetPhotoPath(const BString & path) +{ + fPhotoPath = path; +} diff --git a/libs/libjabber/JabberPresence.h b/libs/libjabber/JabberPresence.h new file mode 100644 index 0000000..b025a4c --- /dev/null +++ b/libs/libjabber/JabberPresence.h @@ -0,0 +1,47 @@ +#ifndef JABBER_PRESENCE_H +#define JABBER_PRESENCE_H + +#include + +class JabberPresence +{ +public: + JabberPresence(); + // Copy constructor + JabberPresence(const JabberPresence &); + ~JabberPresence(); + + void operator=(const JabberPresence & rhs); + + int32 GetShow() const; + BString GetType() const; + BString GetStatus() const; + BString GetJid() const; + BString GetResource() const; + + BString GetPhotoSHA1() const; + BString GetPhotoPath() const; + + void SetPhotoSHA1(const BString & sha1); + void SetPhotoPath(const BString & path); + + void SetShowFromString(const BString & show); + void SetShow(int32 show); + void SetType(const BString & type); + void SetStatus(const BString & status); + void SetJid(const BString & jid); + void SetResource(const BString & resource); + + void ParseFrom(const BString & from); + void PrintToStream(); +private: + BString fStatus; + BString fJid; + BString fType; + int32 fShow; + BString fResource; + BString fPhotoSHA1; + BString fPhotoPath; +}; + +#endif // JABBER_PRESENCE_H diff --git a/libs/libjabber/JabberRegistration.cpp b/libs/libjabber/JabberRegistration.cpp new file mode 100644 index 0000000..1ef9e7d --- /dev/null +++ b/libs/libjabber/JabberRegistration.cpp @@ -0,0 +1,111 @@ +#include "JabberRegistration.h" +#include "Logger.h" + +JabberRegistration::JabberRegistration(const BString & jid, bool unRegister) +{ + fJid = jid; + fUnRegister = unRegister; + fInstructions = ""; + fFields = new FieldList; +} + +void +JabberRegistration::PrintToStream() +{ + logmsg(" ** JabberRegistration **"); + logmsg(" fJid: %s",fJid.String()); + logmsg(" fInstructions: %s",fInstructions.String()); + logmsg(" ** JabberRegistrationFields **"); + +} +JabberRegistration::~JabberRegistration() +{ + delete fFields; +} + +void +JabberRegistration::SetJid(const BString & jid) +{ + fJid = jid; +} + +void +JabberRegistration::SetInstructions(const BString & instructions) +{ + fInstructions = instructions; +} + +void +JabberRegistration::AddField(const BString & field, const BString & value) +{ + FieldPair p; + p.first = field; + p.second = value; + fFields->insert(p); + + logmsg("Field added %s %s",field.String(),value.String()); +} + +void +JabberRegistration::SetFieldValue(const BString & field, const BString & value, bool create) +{ + FieldList::iterator i = fFields->find(field); + if (i == fFields->end()) // not found? + { + if (create) + AddField(field, value); + return; + } + FieldPair pair = *i; + fFields->erase(i); + pair.second = value; + fFields->insert(pair); +} + +bool +JabberRegistration::GetFieldValue(const BString & fieldName, BString & ret) +{ + FieldList::iterator i = fFields->find(fieldName); + if (i != fFields->end()) + { + ret = (*i).second; + return true; + } + + return false; +} + +BString +JabberRegistration::GetJid() const +{ + return fJid; +} + +bool +JabberRegistration::UnRegister() const +{ + return fUnRegister; +} + +JabberRegistration::FieldList * +JabberRegistration::GetFields() const +{ + return fFields; +} + +BString +JabberRegistration::GetInstructions() const +{ + return fInstructions; +} + +bool +JabberRegistration::HasValues() const +{ + if (fFields->size() > 0) + { + if ((*(fFields->begin())).second != "") + return true; + } + return false; +} diff --git a/libs/libjabber/JabberRegistration.h b/libs/libjabber/JabberRegistration.h new file mode 100644 index 0000000..bf7764a --- /dev/null +++ b/libs/libjabber/JabberRegistration.h @@ -0,0 +1,46 @@ +#ifndef JABBER_REGISTRATION_H +#define JABBER_REGISTRATION_H + +#include + +#include +using std::map; +using std::pair; + +class JabberRegistration +{ +public: + JabberRegistration(const BString & jid = "", bool unRegister = false); + ~JabberRegistration(); + + typedef map FieldList; + typedef pair FieldPair; + + FieldList* GetFields() const; + bool GetFieldValue(const BString & fieldName, BString & ret); + BString GetJid() const; + BString GetInstructions() const; + + bool UnRegister() const; + // Creates a field + void AddField(const BString & field, const BString & value); + //void AddFieldValue(const BString & value); + // Sets the value of an existant field + void SetFieldValue(const BString & field, const BString & value, bool create); + + void SetJid(const BString & jid); + void SetInstructions(const BString & instructions); + + bool HasValues() const; + + void PrintToStream(); + +private: + bool fUnRegister; + BString fJid; + BString fInstructions; + FieldList * fFields; +}; + + +#endif diff --git a/libs/libjabber/JabberSSLPlug.cpp b/libs/libjabber/JabberSSLPlug.cpp new file mode 100644 index 0000000..495649c --- /dev/null +++ b/libs/libjabber/JabberSSLPlug.cpp @@ -0,0 +1,188 @@ +#include "JabberSSLPlug.h" +#include "JabberHandler.h" +#include "Logger.h" + +#define msnmsgPing 'ping' + +JabberSSLPlug::JabberSSLPlug(BString forceserver, int32 port){ + + bio = NULL; + ctx = NULL; + + ffServer = forceserver; + ffPort = port; + + Run(); + + fKeepAliveRunner = new BMessageRunner(BMessenger(NULL, (BLooper *)this), + new BMessage(msnmsgPing), 60000000, -1); + + /* Set up the library */ + SSL_library_init(); + ERR_load_BIO_strings(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); +} + + +JabberSSLPlug::~JabberSSLPlug(){ + + if ( fKeepAliveRunner) + delete fKeepAliveRunner; + if(bio != NULL && ctx !=NULL) StopConnection(); +} + +void +JabberSSLPlug::MessageReceived(BMessage* msg){ + + if(msg->what == msnmsgPing){ + Send(" "); + } + else + BLooper::MessageReceived(msg); + +} +int +JabberSSLPlug::StartConnection(BString fServer, int32 fPort,void* cookie){ + + StopConnection(); + + BString fHost; + + if(ffServer!="") + fHost << ffServer << ":" << ffPort; + else + fHost << fServer << ":" << fPort; + + logmsg("StartConnection to %s",fHost.String()); + + SSL * ssl; + int result = 0; + + /* Set up the SSL context */ + + ctx = SSL_CTX_new(SSLv23_client_method()); + + bio = BIO_new_ssl_connect(ctx); + + /* Set the SSL_MODE_AUTO_RETRY flag */ + + BIO_get_ssl(bio, & ssl); + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + + /* Create and setup the connection */ + + + BIO_set_conn_hostname(bio, fHost.String()); + + if(BIO_do_connect(bio) <= 0) + { + logmsg("Error attempting to connect"); + ERR_print_errors_fp(stderr); + BIO_free_all(bio); + SSL_CTX_free(ctx); + bio = NULL; + ctx = NULL; + result = -1; + } + + if (result != -1) + { + fCookie = cookie; + + fReceiverThread = spawn_thread (ReceiveData, "opensll receiver", B_LOW_PRIORITY, this); + + if (fReceiverThread != B_ERROR) + resume_thread(fReceiverThread); + else + { + logmsg("failed to resume the thread!"); + ERR_print_errors_fp(stderr); + BIO_free_all(bio); + SSL_CTX_free(ctx); + bio = NULL; + ctx = NULL; + result = -1; + } + } + + logmsg("DONE: StartConnection to %s",fHost.String()); + fStartConnectionStatus = result; + return result; +} + +/* static function called by the therad.*/ +int32 +JabberSSLPlug::ReceiveData(void * pHandler){ + + char data[1024]; + int length = 0; + JabberSSLPlug * plug = reinterpret_cast(pHandler); + + while (true) + { + + if ((length = (int)BIO_read(plug->bio, data, 1023) ) > 0) + { + data[length] = 0; + logmsg("SSLPlug<<\n%s", data); + } + else + { + if(!BIO_should_retry(plug->bio)) + { + //uhm really and error! + logmsg("SSLPlug ERROR READING! (maybe dropped connection?)"); + ERR_print_errors(plug->bio); + plug->ReceivedData(NULL, 0); + return 0; + } + } + plug->ReceivedData(data,length); + } + return 0; +} + +void +JabberSSLPlug::ReceivedData(const char* data, int32 len){ + JabberHandler * handler = reinterpret_cast(fCookie); + if(handler) + handler->ReceivedData(data,len); +} + + +int +JabberSSLPlug::Send(const BString & xml) +{ + if (fStartConnectionStatus == -1) + return 0; + + logmsg("SSLPlug>>\n%s", xml.String()); + return BIO_write(bio, xml.String(), xml.Length()); +} + +int +JabberSSLPlug::StopConnection() +{ + if(fReceiverThread) + { + //Thread Killing! + suspend_thread(fReceiverThread); + kill_thread(fReceiverThread); + } + + fReceiverThread=0; + fStartConnectionStatus = 0; + + BIO_free_all(bio); + SSL_CTX_free(ctx); + + bio = NULL; + ctx = NULL; + + return 0; +} + + +//-- + diff --git a/libs/libjabber/JabberSSLPlug.h b/libs/libjabber/JabberSSLPlug.h new file mode 100644 index 0000000..31e5514 --- /dev/null +++ b/libs/libjabber/JabberSSLPlug.h @@ -0,0 +1,53 @@ +/* + + JabberSSLPlug (written for GoogleTalk compatibility) + + 22 sept. 2005 by Andrea Anzani (andrea@tenar.it) +*/ +#ifndef JabberSSLPlug_H_ +#define JabberSSLPlug_H_ + +#include "JabberPlug.h" + +#include +#include +#include + +#include + +#include +#include + +// public JabberPlug +class JabberSSLPlug : public BLooper, public JabberPlug { + + public: + JabberSSLPlug(BString forceserver=NULL,int32 port=0); + ~JabberSSLPlug(); + //private: + + int StartConnection(BString fHost, int32 fPort,void* cook);//if >= 0 it's ok. + static int32 ReceiveData(void *); //thread called function + int Send(const BString & xml); //if >= 0 it's ok. + int StopConnection(); + + void ReceivedData(const char* data, int32); + + void MessageReceived(BMessage* ); + private: + + + BIO* bio; + SSL_CTX* ctx; + + BString ffServer; + int32 ffPort; + volatile thread_id fReceiverThread; + void* fCookie; //FIX! + BMessageRunner* fKeepAliveRunner; + int fStartConnectionStatus; +}; + +#endif + +//-- diff --git a/libs/libjabber/JabberSocketPlug.cpp b/libs/libjabber/JabberSocketPlug.cpp new file mode 100644 index 0000000..1fc5c82 --- /dev/null +++ b/libs/libjabber/JabberSocketPlug.cpp @@ -0,0 +1,187 @@ +#include "JabberSocketPlug.h" +#include "Logger.h" + +#ifdef NETSERVER_BUILD +# include +# include +# include +#endif + +#ifdef BONE_BUILD +# include +# include +# include +# include +#endif + +#ifdef __HAIKU__ +# include +# include +# include +#endif + +#include "JabberHandler.h" + +JabberSocketPlug::JabberSocketPlug(){ + + fReceiverThread = -1; + fSocket = -1; + + #ifdef NETSERVER_BUILD + fEndpointLock = new BLocker(); + #endif +} + +JabberSocketPlug::~JabberSocketPlug(){ +} + +int +JabberSocketPlug::StartConnection(BString fHost, int32 fPort,void* cookie){ + + logmsg("StartConnection to %s:%ld",fHost.String(),fPort); + struct sockaddr_in remoteAddr; + remoteAddr.sin_family = AF_INET; + + +#ifdef BONE_BUILD + if (inet_aton(fHost.String(), &remoteAddr.sin_addr) == 0) +#elif NETSERVER_BUILD + if ((int)(remoteAddr.sin_addr.s_addr = inet_addr (fHost.String())) <= 0) +#endif + { + struct hostent * remoteInet(gethostbyname(fHost.String())); + if (remoteInet) + remoteAddr.sin_addr = *((in_addr *)remoteInet->h_addr_list[0]); + else + { + logmsg("failed (remoteInet) [%s]",fHost.String()); + } + } + + remoteAddr.sin_port = htons(fPort); + + if ((fSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + logmsg("failed to create socket"); + fSocket = -1; + } + + if (connect(fSocket, (struct sockaddr *)&remoteAddr, sizeof(remoteAddr)) < 0) + { + logmsg("failed to connect socket"); + fSocket = -1; + } + + + fCookie = cookie; + + fReceiverThread = spawn_thread (ReceiveData, "socket receiver", B_LOW_PRIORITY, this); + + if (fReceiverThread != B_ERROR) + resume_thread(fReceiverThread); + else + { + logmsg("failed to resume the thread!"); + return -1; + } + + logmsg("DONE: StartConnection to %s:%ld",fHost.String(),fPort); + return fSocket; +} + + +int32 +JabberSocketPlug::ReceiveData(void * pHandler){ + + char data[1024]; + int length = 0; + JabberSocketPlug * plug = reinterpret_cast(pHandler); + + while (true) + { + #ifdef NETSERVER_BUILD + plug->fEndpointLock->Lock(); + #endif + + if ((length = (int)recv(plug->fSocket, data, 1023, 0)) > 0) + { + #ifdef NETSERVER_BUILD + plug->fEndpointLock->Unlock(); + #endif + data[length] = 0; + logmsg("SocketPlug<<\n%s", data); + } + else + { + #ifdef NETSERVER_BUILD + plug->fEndpointLock->Unlock(); + #endif + + plug->ReceivedData(NULL,0); + return 0; + } + + + plug->ReceivedData(data,length); + } + + return 0; +} + +void +JabberSocketPlug::ReceivedData(const char* data,int32 len){ + JabberHandler * handler = reinterpret_cast(fCookie); + if(handler) + handler->ReceivedData(data,len); +} + +int +JabberSocketPlug::Send(const BString & xml){ + + if (fSocket) + { + #ifdef NETSERVER + fEndpointLock->Lock(); + #endif + + logmsg("SocketPlug>>\n%s", xml.String()); + + if(send(fSocket, xml.String(), xml.Length(), 0) == -1) + return -1; + + #ifdef NETSERVER_BUILD + fEndpointLock->Unlock(); + #endif + } + + else + + { + logmsg("Socket not initialized"); + return -1; + } + return 0; +} + +int +JabberSocketPlug::StopConnection(){ + + //Thread Killing! + suspend_thread(fReceiverThread); + + if(fReceiverThread) kill_thread(fReceiverThread); + + fReceiverThread=0; + + #ifdef BONE_BUILD + close(fSocket); + #elif NETSERVER_BUILD + closesocket(fSocket); + #endif + + return 0; +} + + +//-- + diff --git a/libs/libjabber/JabberSocketPlug.h b/libs/libjabber/JabberSocketPlug.h new file mode 100644 index 0000000..c3c10bf --- /dev/null +++ b/libs/libjabber/JabberSocketPlug.h @@ -0,0 +1,41 @@ +/* + + JabberSocketPlug (old code BONE/net_server) + + 22 sept. 2005 by Andrea Anzani (andrea@tenar.it) +*/ +#ifndef JabberSocketPlug_H_ +#define JabberSocketPlug_H_ + +#include "JabberPlug.h" +#include + +class JabberSocketPlug : public JabberPlug { + + public: + JabberSocketPlug(); + virtual ~JabberSocketPlug(); + //private: + + int StartConnection(BString fHost, int32 fPort,void* cook);//if >= 0 it's ok. + static int32 ReceiveData(void *); //thread called function + int Send(const BString & xml); //if >= 0 it's ok. + int StopConnection(); + + void ReceivedData(const char* data,int32); + private: + + + int32 fSocket; + volatile thread_id fReceiverThread; + void* fCookie; //FIX! + + #ifdef NETSERVER_BUILD + BLocker * fEndpointLock; + #endif + +}; + +#endif + +//-- diff --git a/libs/libjabber/JabberVCard.cpp b/libs/libjabber/JabberVCard.cpp new file mode 100644 index 0000000..1408205 --- /dev/null +++ b/libs/libjabber/JabberVCard.cpp @@ -0,0 +1,245 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. + * Distributed under the terms of the MIT License. + */ + +#include "JabberVCard.h" +#include "Base64.h" + + +JabberVCard::JabberVCard() +{ +} + + +JabberVCard::JabberVCard(const JabberVCard& copy) +{ + SetFullName(copy.GetFullName()); + SetGivenName(copy.GetGivenName()); + SetFamilyName(copy.GetFamilyName()); + SetMiddleName(copy.GetMiddleName()); + SetNickname(copy.GetNickname()); + SetEmail(copy.GetEmail()); +} + + +void +JabberVCard::operator=(const JabberVCard& vcard) +{ + if (this == &vcard) + return; + + SetFullName(vcard.GetFullName()); + SetGivenName(vcard.GetGivenName()); + SetFamilyName(vcard.GetFamilyName()); + SetMiddleName(vcard.GetMiddleName()); + SetNickname(vcard.GetNickname()); + SetEmail(vcard.GetEmail()); +} + + +BString +JabberVCard::GetJid() const +{ + return fJid; +} + + + +void +JabberVCard::ParseFrom(const BString& from) +{ + fJid = ""; + fResource = ""; + + int32 i = from.FindFirst('/'); + if (i != -1) { + from.CopyInto(fJid, 0, i); + from.CopyInto(fResource, i + 1, from.Length()); + } else + fJid = from; +} + + +BString +JabberVCard::GetFullName() const +{ + return fFullName; +} + + +BString +JabberVCard::GetGivenName() const +{ + return fGivenName; +} + + +BString +JabberVCard::GetFamilyName() const +{ + return fFamilyName; +} + + +BString +JabberVCard::GetMiddleName() const +{ + return fMiddleName; +} + + +BString +JabberVCard::GetNickname() const +{ + return fNickname; +} + + +BString +JabberVCard::GetEmail() const +{ + return fEmail; +} + + +BString +JabberVCard::GetURL() const +{ + return fURL; +} + + +BString +JabberVCard::GetBirthday() const +{ + return fBirthday; +} + + +BString +JabberVCard::GetPhotoMimeType() const +{ + return fPhotoMime; +} + + +BString +JabberVCard::GetPhotoContent() const +{ + return fPhotoContent; +} + + +BString +JabberVCard::GetPhotoURL() const +{ + return fPhotoURL; +} + + +BString +JabberVCard::GetCachedPhotoFile() const +{ + return fCachedPhoto; +} + + +void +JabberVCard::SetFullName(const BString& firstName) +{ + fFullName = firstName; +} + + +void +JabberVCard::SetGivenName(const BString& name) +{ + fGivenName = name; +} + + +void +JabberVCard::SetFamilyName(const BString& name) +{ + fFamilyName = name; +} + + +void +JabberVCard::SetMiddleName(const BString& name) +{ + fMiddleName = name; +} + + +void +JabberVCard::SetNickname(const BString& name) +{ + fNickname = name; +} + + +void +JabberVCard::SetEmail(const BString& email) +{ + fEmail = email; +} + + +void +JabberVCard::SetURL(const BString& url) +{ + fURL = url; +} + + +void +JabberVCard::SetBirthday(const BString& birthday) +{ + fBirthday = birthday; +} + + +void +JabberVCard::SetPhotoMimeType(const BString& mime) +{ + fPhotoMime = mime; + + // We either get base64 encoded data or grab image + // from an URL + fPhotoURL = ""; +} + + +void +JabberVCard::SetPhotoContent(const BString& content) +{ + // Decode base64 + fPhotoContent = Base64::Decode(content); + + // We either get base64 encoded data or grab image + // from an URL + fPhotoURL = ""; +} + + +void +JabberVCard::SetPhotoURL(const BString& url) +{ + fPhotoURL = url; + + // If we previously set the MIME type and/or content + // we must remove them because we either fetch + // the photo from a URL or get it from base64 + // encoded data + fPhotoMime = ""; + fPhotoContent = ""; +} + + +void +JabberVCard::SetCachedPhotoFile(const BString& file) +{ + fCachedPhoto = file; +} diff --git a/libs/libjabber/JabberVCard.h b/libs/libjabber/JabberVCard.h new file mode 100644 index 0000000..fd25267 --- /dev/null +++ b/libs/libjabber/JabberVCard.h @@ -0,0 +1,64 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. + * Distributed under the terms of the MIT License. + */ +#ifndef _JABBER_VCARD_H +#define _JABBER_VCARD_H + +#include + +class JabberVCard { +public: + JabberVCard(); + JabberVCard(const JabberVCard& copy); + + void operator=(const JabberVCard& vcard); + + void ParseFrom(const BString& from); + + BString GetFullName() const; + BString GetGivenName() const; + BString GetFamilyName() const; + BString GetMiddleName() const; + BString GetNickname() const; + BString GetEmail() const; + BString GetURL() const; + BString GetBirthday() const; + BString GetPhotoMimeType() const; + BString GetPhotoContent() const; + BString GetPhotoURL() const; + BString GetCachedPhotoFile() const; + + BString GetJid() const; + + void SetFullName(const BString& firstName); + void SetGivenName(const BString& name); + void SetFamilyName(const BString& name); + void SetMiddleName(const BString& name); + void SetNickname(const BString& name); + void SetEmail(const BString& email); + void SetURL(const BString& url); + void SetBirthday(const BString& birthday); + void SetPhotoMimeType(const BString& mime); + void SetPhotoContent(const BString& content); + void SetPhotoURL(const BString& url); + void SetCachedPhotoFile(const BString& file); + +private: + BString fJid; + BString fResource; + BString fFullName; + BString fGivenName; + BString fFamilyName; + BString fMiddleName; + BString fNickname; + BString fEmail; + BString fURL; + BString fBirthday; + BString fPhotoMime; + BString fPhotoContent; + BString fPhotoURL; + BString fCachedPhoto; +}; + +#endif // _JABBER_VCARD_H diff --git a/libs/libjabber/Jamfile b/libs/libjabber/Jamfile new file mode 100644 index 0000000..483de14 --- /dev/null +++ b/libs/libjabber/Jamfile @@ -0,0 +1,34 @@ +SubDir TOP libs libjabber ; + +SubDirSysHdrs [ FDirName $(TOP) ] ; +SubDirSysHdrs [ FDirName $(TOP) libs ] ; +if $(HAVE_OPENSSL) { + SubDirSysHdrs [ FDirName $(OPENSSL_INCLUDE_DIR) ] ; +} + +SEARCH_SOURCE += [ FDirName $(TOP) libs ] ; + +local sources = + # libjabber + JabberAgent.cpp + JabberContact.cpp + JabberElement.cpp + JabberHandler.cpp + JabberMessage.cpp + JabberPresence.cpp + JabberRegistration.cpp + JabberVCard.cpp + JabberSocketPlug.cpp + Logger.cpp + SHA1.cpp + Base64.cpp + VCardManager.cpp +; + +if $(HAVE_OPENSSL) { + sources += JabberSSLPlug.cpp ; +} + +StaticLibrary libjabber.a : $(sources) ; + + diff --git a/libs/libjabber/LICENSE b/libs/libjabber/LICENSE new file mode 100644 index 0000000..10bad50 --- /dev/null +++ b/libs/libjabber/LICENSE @@ -0,0 +1,33 @@ +// ---------------------- +// Olmeki License +// ---------------------- +// +// Copyright 2002, The Olmeki team. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions, and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions, and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Olmeki team nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/libs/libjabber/Logger.cpp b/libs/libjabber/Logger.cpp new file mode 100644 index 0000000..9ccf920 --- /dev/null +++ b/libs/libjabber/Logger.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com + */ + +#include +#include +#include + +#include +#include +#include + +#include "Logger.h" + + +void +logmsg(const char* message, ...) +{ + va_list varg; + char buffer[2048]; + + va_start(varg, message); + vsprintf(buffer, message, varg); + + char timestr[64]; + char today[11]; + time_t now = time(NULL); + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M", localtime(&now)); + timestr[63] = '\0'; + strftime(today, sizeof(today), "%Y-%m-%d", localtime(&now)); + today[10] = '\0'; + + char filename[B_PATH_NAME_LENGTH]; + snprintf(filename, B_PATH_NAME_LENGTH, "jabber-%s.log", today); + + BPath tempFile; + if (find_directory(B_COMMON_TEMP_DIRECTORY, &tempFile) != B_OK) + debugger("Could not find common temporary folder!"); + tempFile.Append(filename); + + FILE* file = fopen(tempFile.Path(), "a+"); + if (file) { + fprintf(file, "%s %s\n", timestr, buffer); + fclose(file); + } +} diff --git a/libs/libjabber/Logger.h b/libs/libjabber/Logger.h new file mode 100644 index 0000000..96c7e89 --- /dev/null +++ b/libs/libjabber/Logger.h @@ -0,0 +1,10 @@ +/* + * Copyright 2009, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _LOGGER_H +#define _LOGGER_H + +void logmsg(const char* message, ...); + +#endif // _LOGGER_H diff --git a/libs/libjabber/ObjectList.h b/libs/libjabber/ObjectList.h new file mode 100644 index 0000000..a4655d0 --- /dev/null +++ b/libs/libjabber/ObjectList.h @@ -0,0 +1,866 @@ +/* +Open Tracker License + +Terms and Conditions + +Copyright (c) 1991-2000, Be Incorporated. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice applies to all licensees +and shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Be Incorporated shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization from Be Incorporated. + +Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks +of Be Incorporated in the United States and other countries. Other brand product +names are registered trademarks or trademarks of their respective holders. +All rights reserved. +*/ + +/**************************************************************************** +** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** +** ** +** DANGER, WILL ROBINSON! ** +** ** +** The interfaces contained here are part of BeOS's ** +** ** +** >> PRIVATE NOT FOR PUBLIC USE << ** +** ** +** implementation. ** +** ** +** These interfaces WILL CHANGE in future releases. ** +** If you use them, your app WILL BREAK at some future time. ** +** ** +** (And yes, this does mean that binaries built from OpenTracker will not ** +** be compatible with some future releases of the OS. When that happens, ** +** we will provide an updated version of this file to keep compatibility.) ** +** ** +** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** +****************************************************************************/ + +// +// ObjectList is a wrapper around BList that adds type safety, +// optional object ownership, search, insert operations, etc. +// + +#ifndef __OBJECT_LIST__ +#define __OBJECT_LIST__ + +#ifndef _BE_H +#include +#endif + +#include + + +template class BObjectList; + +template +struct UnaryPredicate { + + virtual int operator()(const T *) const + // virtual could be avoided here if FindBinaryInsertionIndex, + // etc. were member template functions + { return 0; } + +private: + static int _unary_predicate_glue(const void *item, void *context); + +friend class BObjectList; +}; + +template +int +UnaryPredicate::_unary_predicate_glue(const void *item, void *context) +{ + return ((UnaryPredicate *)context)->operator()((const T *)item); +} + + +class _PointerList_ : public BList { +public: + _PointerList_(const _PointerList_ &list); + _PointerList_(int32 itemsPerBlock = 20, bool owning = false); + ~_PointerList_(); + + typedef void *(* GenericEachFunction)(void *, void *); + typedef int (* GenericCompareFunction)(const void *, const void *); + typedef int (* GenericCompareFunctionWithState)(const void *, const void *, + void *); + typedef int (* UnaryPredicateGlue)(const void *, void *); + + void *EachElement(GenericEachFunction, void *); + void SortItems(GenericCompareFunction); + void SortItems(GenericCompareFunctionWithState, void *state); + void HSortItems(GenericCompareFunction); + void HSortItems(GenericCompareFunctionWithState, void *state); + + void *BinarySearch(const void *, GenericCompareFunction) const; + void *BinarySearch(const void *, GenericCompareFunctionWithState, void *state) const; + + int32 BinarySearchIndex(const void *, GenericCompareFunction) const; + int32 BinarySearchIndex(const void *, GenericCompareFunctionWithState, void *state) const; + int32 BinarySearchIndexByPredicate(const void *, UnaryPredicateGlue) const; + + bool Owning() const; + bool ReplaceItem(int32, void *); + +protected: + bool owning; + +}; + +template +class BObjectList : private _PointerList_ { +public: + + // iteration and sorting + typedef T *(* EachFunction)(T *, void *); + typedef const T *(* ConstEachFunction)(const T *, void *); + typedef int (* CompareFunction)(const T *, const T *); + typedef int (* CompareFunctionWithState)(const T *, const T *, void *state); + + BObjectList(int32 itemsPerBlock = 20, bool owning = false); + BObjectList(const BObjectList &list); + // clones list; if list is owning, makes copies of all + // the items + + virtual ~BObjectList(); + + BObjectList &operator=(const BObjectList &list); + // clones list; if list is owning, makes copies of all + // the items + + // adding and removing + // ToDo: + // change Add calls to return const item + bool AddItem(T *); + bool AddItem(T *, int32); + bool AddList(BObjectList *); + bool AddList(BObjectList *, int32); + + bool RemoveItem(T *, bool deleteIfOwning = true); + // if owning, deletes the removed item + T *RemoveItemAt(int32); + // returns the removed item + + void MakeEmpty(); + + // item access + T *ItemAt(int32) const; + + bool ReplaceItem(int32 index, T *); + // if list is owning, deletes the item at first + T *SwapWithItem(int32 index, T *newItem); + // same as ReplaceItem, except does not delete old item at , + // returns it instead + + T *FirstItem() const; + T *LastItem() const; + + // misc. getters + int32 IndexOf(const T *) const; + bool HasItem(const T *) const; + bool IsEmpty() const; + int32 CountItems() const; + + T *EachElement(EachFunction, void *); + const T *EachElement(ConstEachFunction, void *) const; + + void SortItems(CompareFunction); + void SortItems(CompareFunctionWithState, void *state); + void HSortItems(CompareFunction); + void HSortItems(CompareFunctionWithState, void *state); + + // linear search, returns first item that matches predicate + const T *FindIf(const UnaryPredicate &) const; + T *FindIf(const UnaryPredicate &); + + // list must be sorted with CompareFunction for these to work + T *BinarySearch(const T &, CompareFunction) const; + T *BinarySearch(const T &, CompareFunctionWithState, void *state) const; + + template + T *BinarySearchByKey(const Key &key, int (*compare)(const Key *, const T *)) + const; + + template + T *BinarySearchByKey(const Key &key, + int (*compare)(const Key *, const T *, void *), void *state) const; + + int32 BinarySearchIndex(const T &item, CompareFunction compare) const; + int32 BinarySearchIndex(const T &item, CompareFunctionWithState compare, + void *state) const; + + template + int32 BinarySearchIndexByKey(const Key &key, + int (*compare)(const Key *, const T *)) const; + + // Binary insertion - list must be sorted with CompareFunction for + // these to work + + // simple insert + bool BinaryInsert(T *, CompareFunction); + bool BinaryInsert(T *, CompareFunctionWithState, void *state); + bool BinaryInsert(T *, const UnaryPredicate &); + + // unique insert, returns false if item already in list + bool BinaryInsertUnique(T *, CompareFunction); + bool BinaryInsertUnique(T *, CompareFunctionWithState, void *state); + bool BinaryInsertUnique(T *, const UnaryPredicate &); + + // insert a copy of the item, returns new inserted item + T *BinaryInsertCopy(const T ©This, CompareFunction); + T *BinaryInsertCopy(const T ©This, CompareFunctionWithState, void *state); + + // insert a copy of the item if not in list already + // returns new inserted item or existing item in case of a conflict + T *BinaryInsertCopyUnique(const T ©This, CompareFunction); + T *BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState, void *state); + + int32 FindBinaryInsertionIndex(const UnaryPredicate &, bool *alreadyInList = 0) const; + // returns either the index into which a new item should be inserted + // or index of an existing item that matches the predicate + + // deprecated API, will go away + BList *AsBList() + { return this; } + const BList *AsBList() const + { return this; } +private: + void SetItem(int32, T *); +}; + +template +Result +WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1), Param1 p1) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (list->ItemAt(index)->*func)(p1)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1), Param1 p1) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1, Param2), + Param1 p1, Param2 p2) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (list->ItemAt(index)->*func)(p1, p2)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2), + Param1 p1, Param2 p2) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1, p2)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2, + Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1, p2, p3, p4)) != 0) + break; + + return result; +} + +template +void +EachListItemIgnoreResult(BObjectList *list, Result (Item::*func)()) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (list->ItemAt(index)->*func)(); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *, Param1), Param1 p1) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1); +} + +template +void +EachListItem(BObjectList *list, void (Item::*func)(Param1, Param2), + Param1 p1, Param2 p2) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (list->ItemAt(index)->*func)(p1, p2); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2), + Param1 p1, Param2 p2) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, + Param3), Param1 p1, Param2 p2, Param3 p3) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2, p3); +} + + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, + Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2, p3, p4); +} + +// inline code + +inline bool +_PointerList_::Owning() const +{ + return owning; +} + +template +BObjectList::BObjectList(int32 itemsPerBlock, bool owning) + : _PointerList_(itemsPerBlock, owning) +{ +} + +template +BObjectList::BObjectList(const BObjectList &list) + : _PointerList_(list) +{ + owning = list.owning; + if (owning) { + // make our own copies in an owning list + int32 count = list.CountItems(); + for (int32 index = 0; index < count; index++) { + T *item = list.ItemAt(index); + if (item) + item = new T(*item); + SetItem(index, item); + } + } +} + +template +BObjectList::~BObjectList() +{ + if (Owning()) + // have to nuke elements first + MakeEmpty(); +} + +template +BObjectList & +BObjectList::operator=(const BObjectList &list) +{ + owning = list.owning; + BObjectList &result = (BObjectList &)_PointerList_::operator=(list); + if (owning) { + // make our own copies in an owning list + int32 count = list.CountItems(); + for (int32 index = 0; index < count; index++) { + T *item = list.ItemAt(index); + if (item) + item = new T(*item); + SetItem(index, item); + } + } + return result; +} + +template +bool +BObjectList::AddItem(T *item) +{ + // need to cast to void * to make T work for const pointers + return _PointerList_::AddItem((void *)item); +} + +template +bool +BObjectList::AddItem(T *item, int32 atIndex) +{ + return _PointerList_::AddItem((void *)item, atIndex); +} + +template +bool +BObjectList::AddList(BObjectList *newItems) +{ + return _PointerList_::AddList(newItems); +} + +template +bool +BObjectList::AddList(BObjectList *newItems, int32 atIndex) +{ + return _PointerList_::AddList(newItems, atIndex); +} + + +template +bool +BObjectList::RemoveItem(T *item, bool deleteIfOwning) +{ + bool result = _PointerList_::RemoveItem((void *)item); + + if (result && Owning() && deleteIfOwning) + delete item; + + return result; +} + +template +T * +BObjectList::RemoveItemAt(int32 index) +{ + return (T *)_PointerList_::RemoveItem(index); +} + +template +inline T * +BObjectList::ItemAt(int32 index) const +{ + return (T *)_PointerList_::ItemAt(index); +} + +template +bool +BObjectList::ReplaceItem(int32 index, T *item) +{ + if (owning) + delete ItemAt(index); + return _PointerList_::ReplaceItem(index, (void *)item); +} + +template +T * +BObjectList::SwapWithItem(int32 index, T *newItem) +{ + T *result = ItemAt(index); + _PointerList_::ReplaceItem(index, (void *)newItem); + return result; +} + +template +void +BObjectList::SetItem(int32 index, T *newItem) +{ + _PointerList_::ReplaceItem(index, (void *)newItem); +} + +template +int32 +BObjectList::IndexOf(const T *item) const +{ + return _PointerList_::IndexOf((void *)item); +} + +template +T * +BObjectList::FirstItem() const +{ + return (T *)_PointerList_::FirstItem(); +} + +template +T * +BObjectList::LastItem() const +{ + return (T *)_PointerList_::LastItem(); +} + +template +bool +BObjectList::HasItem(const T *item) const +{ + return _PointerList_::HasItem((void *)item); +} + +template +bool +BObjectList::IsEmpty() const +{ + return _PointerList_::IsEmpty(); +} + +template +int32 +BObjectList::CountItems() const +{ + return _PointerList_::CountItems(); +} + +template +void +BObjectList::MakeEmpty() +{ + if (owning) { + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + delete ItemAt(index); + } + _PointerList_::MakeEmpty(); +} + +template +T * +BObjectList::EachElement(EachFunction func, void *params) +{ + return (T *)_PointerList_::EachElement((GenericEachFunction)func, params); +} + + +template +const T * +BObjectList::EachElement(ConstEachFunction func, void *params) const +{ + return (const T *) + const_cast *>(this)->_PointerList_::EachElement( + (GenericEachFunction)func, params); +} + +template +const T * +BObjectList::FindIf(const UnaryPredicate &predicate) const +{ + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + if (predicate.operator()(ItemAt(index)) == 0) + return ItemAt(index); + return 0; +} + +template +T * +BObjectList::FindIf(const UnaryPredicate &predicate) +{ + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + if (predicate.operator()(ItemAt(index)) == 0) + return ItemAt(index); + return 0; +} + + +template +void +BObjectList::SortItems(CompareFunction function) +{ + _PointerList_::SortItems((GenericCompareFunction)function); +} + +template +void +BObjectList::SortItems(CompareFunctionWithState function, void *state) +{ + _PointerList_::SortItems((GenericCompareFunctionWithState)function, state); +} + +template +void +BObjectList::HSortItems(CompareFunction function) +{ + _PointerList_::HSortItems((GenericCompareFunction)function); +} + +template +void +BObjectList::HSortItems(CompareFunctionWithState function, void *state) +{ + _PointerList_::HSortItems((GenericCompareFunctionWithState)function, state); +} + +template +T * +BObjectList::BinarySearch(const T &key, CompareFunction func) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunction)func); +} + +template +T * +BObjectList::BinarySearch(const T &key, CompareFunctionWithState func, void *state) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunctionWithState)func, state); +} + + +template +template +T * +BObjectList::BinarySearchByKey(const Key &key, + int (*compare)(const Key *, const T *)) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunction)compare); +} + + +template +template +T * +BObjectList::BinarySearchByKey(const Key &key, + int (*compare)(const Key *, const T *, void *), void *state) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunctionWithState)compare, state); +} + + +template +int32 +BObjectList::BinarySearchIndex(const T &item, CompareFunction compare) const +{ + return _PointerList_::BinarySearchIndex(&item, + (GenericCompareFunction)compare); +} + + +template +int32 +BObjectList::BinarySearchIndex(const T &item, + CompareFunctionWithState compare, void *state) const +{ + return _PointerList_::BinarySearchIndex(&item, + (GenericCompareFunctionWithState)compare, state); +} + + +template +template +int32 +BObjectList::BinarySearchIndexByKey(const Key &key, + int (*compare)(const Key *, const T *)) const +{ + return _PointerList_::BinarySearchIndex(&key, + (GenericCompareFunction)compare); +} + + +template +bool +BObjectList::BinaryInsert(T *item, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunction)func); + if (index >= 0) { + // already in list, add after existing + return AddItem(item, index + 1); + } + + return AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsert(T *item, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) { + // already in list, add after existing + return AddItem(item, index + 1); + } + + return AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunction)func); + if (index >= 0) + return false; + + return AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + return false; + + return AddItem(item, -index - 1); +} + + +template +T * +BObjectList::BinaryInsertCopy(const T ©This, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunction)func); + + if (index >= 0) + index++; + else + index = -index - 1; + + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopy(const T ©This, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunctionWithState)func, state); + + if (index >= 0) + index++; + else + index = -index - 1; + + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunction)func); + if (index >= 0) + return ItemAt(index); + + index = -index - 1; + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState func, + void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + return ItemAt(index); + + index = -index - 1; + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +int32 +BObjectList::FindBinaryInsertionIndex(const UnaryPredicate &pred, bool *alreadyInList) + const +{ + int32 index = _PointerList_::BinarySearchIndexByPredicate(&pred, + (UnaryPredicateGlue)&UnaryPredicate::_unary_predicate_glue); + + if (alreadyInList) + *alreadyInList = index >= 0; + + if (index < 0) + index = -index - 1; + + return index; +} + +template +bool +BObjectList::BinaryInsert(T *item, const UnaryPredicate &pred) +{ + return AddItem(item, FindBinaryInsertionIndex(pred)); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, const UnaryPredicate &pred) +{ + bool alreadyInList; + int32 index = FindBinaryInsertionIndex(pred, &alreadyInList); + if (alreadyInList) + return false; + + AddItem(item, index); + return true; +} + +#endif /* __OBJECT_LIST__ */ diff --git a/libs/libjabber/SHA1.cpp b/libs/libjabber/SHA1.cpp new file mode 100644 index 0000000..94bdf96 --- /dev/null +++ b/libs/libjabber/SHA1.cpp @@ -0,0 +1,222 @@ +/* + 100% free public domain implementation of the SHA-1 + algorithm by Dominik Reichl + + + === Test Vectors (from FIPS PUB 180-1) === + + "abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + + A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + + +#include "SHA1.h" + + +CSHA1::CSHA1() +{ + Reset(); +} + +CSHA1::~CSHA1() +{ + Reset(); +} + + +void CSHA1::Reset() +{ + // SHA1 initialization constants + m_state[0] = 0x67452301; + m_state[1] = 0xEFCDAB89; + m_state[2] = 0x98BADCFE; + m_state[3] = 0x10325476; + m_state[4] = 0xC3D2E1F0; + + m_count[0] = 0; + m_count[1] = 0; +} + +void CSHA1::Transform(unsigned long state[5], unsigned char buffer[64]) +{ + unsigned long a = 0, b = 0, c = 0, d = 0, e = 0; + + SHA1_WORKSPACE_BLOCK* block; + static unsigned char workspace[64]; + block = (SHA1_WORKSPACE_BLOCK*)workspace; + memcpy(block, buffer, 64); + + // Copy state[] to working vars + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + // 4 rounds of 20 operations each. Loop unrolled. + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + // Add the working vars back into state[] + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + // Wipe variables + a = 0; b = 0; c = 0; d = 0; e = 0; +} + +// Use this function to hash in binary data and strings +void CSHA1::Update(unsigned char* data, unsigned int len) +{ + unsigned long i = 0, j = 0; + + j = (m_count[0] >> 3) & 63; + + if((m_count[0] += len << 3) < (len << 3)) m_count[1]++; + + m_count[1] += (len >> 29); + + if((j + len) > 63) + { + memcpy(&m_buffer[j], data, (i = 64 - j)); + Transform(m_state, m_buffer); + + for (; i+63 < len; i += 64) + { + Transform(m_state, &data[i]); + } + + j = 0; + } + else i = 0; + + memcpy(&m_buffer[j], &data[i], len - i); +} + +// Hash in file contents +bool CSHA1::HashFile(char *szFileName) +{ + unsigned long ulFileSize = 0, ulRest = 0, ulBlocks = 0; + unsigned long i = 0; + unsigned char uData[MAX_FILE_READ_BUFFER]; + FILE *fIn = NULL; + + if((fIn = fopen(szFileName, "rb")) == NULL) return(false); + + fseek(fIn, 0, SEEK_END); + ulFileSize = ftell(fIn); + fseek(fIn, 0, SEEK_SET); + + ulRest = ulFileSize % MAX_FILE_READ_BUFFER; + ulBlocks = ulFileSize / MAX_FILE_READ_BUFFER; + + for(i = 0; i < ulBlocks; i++) + { + fread(uData, 1, MAX_FILE_READ_BUFFER, fIn); + Update(uData, MAX_FILE_READ_BUFFER); + } + + if(ulRest != 0) + { + fread(uData, 1, ulRest, fIn); + Update(uData, ulRest); + } + + fclose(fIn); + fIn = NULL; + + return(true); +} + +void CSHA1::Final() +{ + unsigned long i = 0, j = 0; + unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (i = 0; i < 8; i++) + finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)] + >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent + + Update((unsigned char *)"\200", 1); + + while ((m_count[0] & 504) != 448) + Update((unsigned char *)"\0", 1); + + Update(finalcount, 8); // Cause a SHA1Transform() + + for (i = 0; i < 20; i++) + { + m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255); + } + + // Wipe variables for security reasons + i = 0; j = 0; + memset(m_buffer, 0, 64); + memset(m_state, 0, 20); + memset(m_count, 0, 8); + memset(finalcount, 0, 8); + + Transform(m_state, m_buffer); +} + +// Get the final hash as a pre-formatted string +void CSHA1::ReportHash(char *szReport, unsigned char uReportType) +{ + unsigned char i = 0; + + if(uReportType == REPORT_HEX) + { + sprintf(szReport, "%02X", m_digest[0]); + + for(i = 1; i < 20; i++) + { + sprintf(szReport, "%s%02X", szReport, m_digest[i]); + } + } + else if(uReportType == REPORT_DIGIT) + { + sprintf(szReport, "%u", m_digest[0]); + + for(i = 1; i < 20; i++) + { + sprintf(szReport, "%s %u", szReport, m_digest[i]); + } + } + else sprintf(szReport, "Error: Unknown report type!"); +} + +// Get the raw message digest +void CSHA1::GetHash(unsigned char *uDest) +{ + unsigned char i = 0; + + for(i = 0; i < 20; i++) + uDest[i] = m_digest[i]; +} diff --git a/libs/libjabber/SHA1.h b/libs/libjabber/SHA1.h new file mode 100644 index 0000000..8db7324 --- /dev/null +++ b/libs/libjabber/SHA1.h @@ -0,0 +1,81 @@ +/* + 100% free public domain implementation of the SHA-1 + algorithm by Dominik Reichl + + + === Test Vectors (from FIPS PUB 180-1) === + + "abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + + A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#ifndef ___SHA1_H___ +#define ___SHA1_H___ + +#include // Needed for file access +#include // Needed for memset and memcpy + +//#define LITTLE_ENDIAN +#define MAX_FILE_READ_BUFFER 8000 + +class CSHA1 +{ +public: + // Rotate x bits to the left + #define ROL32(value, bits) (((value)<<(bits))|((value)>>(32-(bits)))) + + #ifdef LITTLE_ENDIAN + #define SHABLK0(i) (block->l[i] = (ROL32(block->l[i],24) & 0xFF00FF00) | (ROL32(block->l[i],8) & 0x00FF00FF)) + #else + #define SHABLK0(i) (block->l[i]) + #endif + + #define SHABLK(i) (block->l[i&15] = ROL32(block->l[(i+13)&15] ^ block->l[(i+8)&15] ^ block->l[(i+2)&15] ^ block->l[i&15],1)) + + // SHA-1 rounds + #define R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } + #define R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } + #define R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); } + #define R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); } + #define R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); } + + typedef union { + unsigned char c[64]; + unsigned long l[16]; + } SHA1_WORKSPACE_BLOCK; + + // Two different formats for ReportHash(...) + enum { REPORT_HEX = 0, REPORT_DIGIT = 1 }; + + // Constructor and Destructor + CSHA1(); + virtual ~CSHA1(); + + unsigned long m_state[5]; + unsigned long m_count[2]; + unsigned char m_buffer[64]; + unsigned char m_digest[20]; + + void Reset(); + + // Update the hash value + void Update(unsigned char* data, unsigned int len); + bool HashFile(char *szFileName); + + // Finalize hash and report + void Final(); + void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX); + void GetHash(unsigned char *uDest); + +private: + // Private SHA-1 transformation + void Transform(unsigned long state[5], unsigned char buffer[64]); +}; + +#endif // ___SHA1_H___ diff --git a/libs/libjabber/ServerHandler.h b/libs/libjabber/ServerHandler.h new file mode 100644 index 0000000..a1de077 --- /dev/null +++ b/libs/libjabber/ServerHandler.h @@ -0,0 +1,7 @@ +#include "JabberAgent.h" +#include "JabberContact.h" +#include "JabberElement.h" +#include "JabberHandler.h" +#include "JabberMessage.h" +#include "JabberPresence.h" +#include "JabberRegistration.h" diff --git a/libs/libjabber/States.h b/libs/libjabber/States.h new file mode 100644 index 0000000..a72533a --- /dev/null +++ b/libs/libjabber/States.h @@ -0,0 +1,18 @@ +/* + * Copyright 2009, Andrea Anzani. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _STATES_H +#define _STATES_H + +#include + +const int32 S_OFFLINE = 0x0; +const int32 S_ONLINE = 0x1; +const int32 S_AWAY = 0x2; +const int32 S_XA = 0x3; +const int32 S_DND = 0x4; +const int32 S_CHAT = 0x5; +const int32 S_SEND = 0x6; + +#endif // _STATES_H diff --git a/libs/libjabber/VCardManager.cpp b/libs/libjabber/VCardManager.cpp new file mode 100644 index 0000000..abc62f0 --- /dev/null +++ b/libs/libjabber/VCardManager.cpp @@ -0,0 +1,139 @@ +#include "VCardManager.h" +#include +#include +#include +#include "JabberPresence.h" +#include "JabberContact.h" +#include "JabberVCard.h" +#include "JabberHandler.h" +#include "Logger.h" +#include +#include "SHA1.h" + +VCardManager::VCardManager(JabberHandler* jabberHandler) : fJabberHandler(jabberHandler) +{ + BPath fCacheFolderPath; + find_directory(B_USER_SETTINGS_DIRECTORY, &fCacheFolderPath); + fCacheFolderPath.Append("libjabber"); + fCacheFolder.SetTo(fCacheFolderPath.Path()); + + fCacheFolder.CreateDirectory(fCacheFolderPath.Path(), &fCacheFolder); + + fCachePath = fCacheFolderPath; + fCachePath.Append("jabber-roster-cache"); + + BFile *file = new BFile(fCachePath.Path(), B_READ_ONLY); + fCache.Unflatten(file); + delete file; +} + +void +VCardManager::SaveCache() +{ + BFile *file = new BFile(fCachePath.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + fCache.Flatten(file); + delete file; +} + +void +VCardManager::VCardReceived(JabberContact* contact) +{ + logmsg("VCardReceived: for %s\n", contact->GetJid().String()); + if (contact->GetVCard()->GetPhotoContent() == "") + return; + + BMessage jid; + if (fCache.FindMessage(contact->GetJid().String(), &jid) != B_OK) + { + fCache.AddMessage(contact->GetJid().String(), &jid); + logmsg("no vCard request in cache! adding..\n"); + SaveCache(); + } + + BString sha1; + if (jid.FindString("photo-sha1", &sha1) != B_OK || sha1 == "" ) + { + // let's try to make an sha1.. + CSHA1 s1; + char hash[256]; + s1.Reset(); + s1.Update((unsigned char*)contact->GetVCard()->GetPhotoContent().String(), contact->GetVCard()->GetPhotoContent().Length()); + s1.Final(); + s1.ReportHash(hash, CSHA1::REPORT_HEX); + sha1.SetTo(hash, 256); + logmsg("sha1 created: %s for %s adding to cache..\n", sha1.String(), contact->GetJid().String()); + jid.AddString("photo-sha1", sha1.String()); + fCache.ReplaceMessage(contact->GetJid().String(), &jid); + SaveCache(); + } + + //save to file. + BPath newFile(&fCacheFolder); + newFile.Append(sha1.String()); + + BFile file(newFile.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + file.Write(contact->GetVCard()->GetPhotoContent().String(), contact->GetVCard()->GetPhotoContent().Length()); + contact->GetVCard()->SetCachedPhotoFile(newFile.Path()); + if (contact->GetJid() != fJabberHandler->GetJid()) + fJabberHandler->GotBuddyPhoto(contact->GetJid(), newFile.Path()); +} + +void +VCardManager::RefinePresence(JabberPresence* presence) +{ + logmsg("RefinePresence: [%s] for %s\n", presence->GetPhotoSHA1().String(), presence->GetJid().String()); + BMessage jid; + if (fCache.FindMessage(presence->GetJid().String(), &jid) != B_OK) + { + logmsg(" not found in cache.. adding\n"); + jid.AddString("photo-sha1", presence->GetPhotoSHA1().String()); + fCache.AddMessage(presence->GetJid().String(), &jid); + jid.PrintToStream(); + SaveCache(); + logmsg("...asking for downloading the image..\n"); + fJabberHandler->RequestVCard(presence->GetJid()); + } + else + { + logmsg("..found in cache!\n"); + BString sha1; + if ( jid.FindString("photo-sha1", &sha1) == B_OK ) + { + if (sha1.ICompare(presence->GetPhotoSHA1()) != 0) + { + logmsg("..existing sha1 is different, asking new vcard..\n"); + jid.ReplaceString("photo-sha1", presence->GetPhotoSHA1().String()); + SaveCache(); + fJabberHandler->RequestVCard(presence->GetJid()); + } + else + { + if (sha1 == "") + { + fJabberHandler->GotBuddyPhoto(presence->GetJid(), ""); + } + else + { + BPath newFile(&fCacheFolder); + newFile.Append(sha1.String()); + logmsg("..sha1 match.. checking if file exits..(%s)\n", newFile.Path()); + if(BEntry(newFile.Path()).Exists()) + { + logmsg(".. yes it exists!\n"); + fJabberHandler->GotBuddyPhoto(presence->GetJid(), newFile.Path()); + } + else + { + logmsg("..no it doesn't, asking new vcard..\n"); + fJabberHandler->RequestVCard(presence->GetJid()); + } + } + } + } + else + { + fJabberHandler->RequestVCard(presence->GetJid()); + } + } + +} diff --git a/libs/libjabber/VCardManager.h b/libs/libjabber/VCardManager.h new file mode 100644 index 0000000..ffdedb9 --- /dev/null +++ b/libs/libjabber/VCardManager.h @@ -0,0 +1,34 @@ +#ifndef VCardManager_H_ +#define VCardManager_H_ + +#include +#include +#include + +class JabberHandler; +class JabberPresence; +class JabberContact; +class JabberVCard; + +class VCardManager +{ + public: + VCardManager(JabberHandler* jabberHandler); + + protected: + friend class JabberHandler; + + void RefinePresence(JabberPresence*); + void VCardReceived(JabberContact*); + + private: + + void SaveCache(); + + JabberHandler* fJabberHandler; + BMessage fCache; + BPath fCachePath; + BDirectory fCacheFolder; + +}; +#endif diff --git a/libs/librunview/Emoconfig.cpp b/libs/librunview/Emoconfig.cpp new file mode 100644 index 0000000..07760bd --- /dev/null +++ b/libs/librunview/Emoconfig.cpp @@ -0,0 +1,195 @@ +#include "Emoconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include "SmileTextRender.h" + +//tmp +BMessage* faces=NULL; +bool valid=false; +bool fname=false; +bool svg=false; +bool size=true; +BString filename; +BString face; +BPath path; +BString gCharacters; + +Emoconfig::Emoconfig(const char* xmlfile):BMessage() +{ + fEmoticonSize = 16.0; //default + numfaces=0; + + fParser = XML_ParserCreate(NULL); + + XML_SetUserData(fParser, this); + XML_SetElementHandler(fParser, StartElement, EndElement); + XML_SetCharacterDataHandler(fParser, Characters); + + //path! + BPath p(xmlfile); + p.GetParent(&path); + + // loading the config file.. + BFile* settings=new BFile(xmlfile,B_READ_ONLY); + off_t size; + settings->GetSize(&size); + if(size) + { + void *buffer=malloc(size); + size=settings->Read(buffer,size); + XML_Parse(fParser, (const char*)buffer, size, true); + free(buffer); + } + delete settings; + + if(fParser) + XML_ParserFree(fParser); + + printf("Emoconfig: loaded %d faces\n", numfaces); + +} + +Emoconfig::~Emoconfig() +{ + +} + +void +Emoconfig::StartElement(void * /*pUserData*/, const char * pName, const char ** /*pAttr*/) +{ + //printf("StartElement %s\n",pName); + BString name(pName); + if(name.ICompare("emoticon")==0) + { + faces=new BMessage(); + svg=false; + } + else + if(name.ICompare("text")==0 && faces) + { + valid=true; + } + else + if(name.ICompare("file")==0 && faces) + { + fname=true; + } else + if(name.ICompare("svg")==0 && faces) + { +// printf("File is SVG\n"); + svg=true; + } else + if(name.ICompare("size")==0) + { + size=true; + gCharacters = ""; + } +} + +void +Emoconfig::EndElement(void * pUserData, const char * pName) +{ + //printf("EndElement %s\n",pName); + BString name(pName); + + if(name.ICompare("emoticon")==0 && faces) + { + //faces->PrintToStream(); //debug + delete faces; + faces=NULL; + + } + else + if(name.ICompare("text")==0 && faces) + { + valid=false; + faces->AddString("face",face); + //printf("to ]%s[\n",face.String()); + face.SetTo(""); + + } + else + if(name.ICompare("file")==0 && faces) + { + //load file + + //compose the filename + BPath p(path); + p.Append(filename.String()); + BBitmap *icons = NULL; + + if ( !svg ) + { // + icons=BTranslationUtils::GetBitmap(p.Path()); + } + + //assign to faces; + fname=false; + +// printf("Filename %s [%s]\n",p.Path(),path.Path()); + if(!icons) return; + + int i=0; + BString s; + while(faces->FindString("face",i,&s)==B_OK) + { + + if(i==0) + { + ((Emoconfig*)pUserData)->menu.AddPointer(s.String(),(const void*)icons); + ((Emoconfig*)pUserData)->menu.AddString("face",s.String()); + } + ((BMessage*)pUserData)->AddPointer(s.String(),(const void*)icons); + ((BMessage*)pUserData)->AddString("face",s.String()); + ((Emoconfig*)pUserData)->numfaces++; + i++; + + } + + + } else + if(name.ICompare("size")==0) + { + if ( size ) + { + ((Emoconfig*)pUserData)->fEmoticonSize = atoi(gCharacters.String()); + } + + size = false; + } + +} + +void +Emoconfig::Characters(void * /*pUserData*/, const char * pString, int pLen) +{ + BString f(pString,pLen); + //printf("Characters %s\n",f.String()); + if(faces && valid) + { + f.RemoveAll(" "); + f.RemoveAll("\""); + if(f.Length()>0) + face.Append(f); + } + else + if(fname) + { + f.RemoveAll(" "); + filename=f; + + } + else + { + gCharacters.Append(f); + } +} + + + diff --git a/libs/librunview/Emoconfig.h b/libs/librunview/Emoconfig.h new file mode 100644 index 0000000..03c324a --- /dev/null +++ b/libs/librunview/Emoconfig.h @@ -0,0 +1,31 @@ +/* i don't like this class name */ + +#ifndef Emoconfig_h_ +#define Emoconfig_h_ + +#include +#include + +class Emoconfig : public BMessage +{ + public: + Emoconfig(const char* xmlfile); + ~Emoconfig(); + int numfaces; + BMessage menu; + + float GetEmoticonSize() { return fEmoticonSize; } + + private: + + float fEmoticonSize; + XML_Parser fParser; + + static void StartElement(void * pUserData, const char * pName, const char ** pAttr); + static void EndElement(void * pUserData, const char * pName); + static void Characters(void * pUserData, const char * pString, int pLen); + +}; + +#endif + diff --git a/libs/librunview/Emoticor.cpp b/libs/librunview/Emoticor.cpp new file mode 100644 index 0000000..9cc579b --- /dev/null +++ b/libs/librunview/Emoticor.cpp @@ -0,0 +1,118 @@ +#include "Emoticor.h" +#include +#include +#include +#include "string.h" + +static Emoticor* fInstance = NULL; + + +Emoticor* +Emoticor::Get() +{ + if (fInstance == NULL) + fInstance = new Emoticor(); + + return fInstance; +} + +Emoticor::Emoticor() +{ + fInstance = NULL; + fConfig = NULL; +} + +Emoticor::~Emoticor() +{ + if (fConfig) + delete fConfig; +} + +Emoconfig* +Emoticor::Config() +{ + return fConfig; +} + +void +Emoticor::LoadConfig(const char* txt) +{ + fConfig = new Emoconfig(txt); +} + +void +Emoticor::_findTokens(RunView *fTextView,BString text,int tokenstart, int16 cols ,int16 font ,int16 cols2 ,int16 font2) +{ + //****************************************** + // "Iteration is human, recursion is divine" + //****************************************** + + + int32 newindex = 0; + BString cur; + int i = tokenstart; + + if (fConfig != NULL) + { + while(fConfig->FindString("face",i,&cur)==B_OK) + //for(int i=tokenstart;inumfaces;i++) + { + i++; + //if(config->FindString("face",i,&cur)!=B_OK) return; + + newindex=0; + + while(true) + { + newindex=text.IFindFirst(cur.String(),0); + //printf("Try %d %s -- match %d\n",i,cur->original.String(),newindex); + + if(newindex!=B_ERROR) + { + //take a walk on the left side ;) + + //printf("Found at %ld \n",newindex); + + if(newindex-1>=0) + { + BString left; + text.CopyInto(left,0,newindex); + //printf("ready to recourse! [%s]\n",left.String()); + _findTokens(fTextView,left,tokenstart+1,cols,font,cols2,font2); + } + + + text.Remove(0,newindex+cur.Length()); + + //printf("remaning [%s] printed [%s]\n",text.String(),cur->original.String()); + + fTextView->Append(cur.String(),cols2,cols2,font2); + + if(text.Length()==0) return; //useless stack + } + else + break; + + } + } + } + + fTextView->Append(text.String(),cols,cols,font); + +} + +void +Emoticor::AddText(RunView *fTextView,const char * txt, int16 cols ,int16 font ,int16 cols2 ,int16 font2 ) +{ + + BString left(txt); + +// if(!fConfig) +// fTextView->Append(txt,cols,cols,font); + + _findTokens(fTextView,left,0,cols,font,cols2,font2); + + return; + +} + diff --git a/libs/librunview/Emoticor.h b/libs/librunview/Emoticor.h new file mode 100644 index 0000000..4780b6a --- /dev/null +++ b/libs/librunview/Emoticor.h @@ -0,0 +1,31 @@ +#ifndef _Emoticor_h_ +#define _Emoticor_h_ + + +#include +#include "RunView.h" +#include "Emoconfig.h" + +class Emoticor +{ + public: + + static Emoticor* Get(); //singleton + + + void AddText(RunView *fTextView,const char* text, int16 cols ,int16 font ,int16 cols2 ,int16 font2 ); + void LoadConfig(const char*); + + Emoconfig *Config(); + + ~Emoticor(); + + private: + Emoticor(); + Emoconfig* fConfig; + void _findTokens(RunView *fTextView,BString text,int tokenstart, int16 cols ,int16 font ,int16 cols2 ,int16 font2); + +}; + +#endif + diff --git a/libs/librunview/Jamfile b/libs/librunview/Jamfile new file mode 100644 index 0000000..8328ecb --- /dev/null +++ b/libs/librunview/Jamfile @@ -0,0 +1,21 @@ +SubDir TOP libs librunview ; + +SubDirSysHdrs [ FDirName $(TOP) ] ; +SubDirSysHdrs [ FDirName $(TOP) libs ] ; + +SEARCH_SOURCE += [ FDirName $(TOP) libs ] ; + +local sources = + # libjabber + Theme.cpp + RunView.cpp + Utilities.cpp + URLCrunch.cpp + Emoticor.cpp + Emoconfig.cpp +; + + +StaticLibrary librunview.a : $(sources) ; + +Depends libjabber.a ; diff --git a/libs/librunview/NormalTextRender.h b/libs/librunview/NormalTextRender.h new file mode 100644 index 0000000..90e68af --- /dev/null +++ b/libs/librunview/NormalTextRender.h @@ -0,0 +1,43 @@ +#ifndef _NormalTextRender_H_ +#define _NormalTextRender_H_ + +#include "TextRender.h" +#include +#include + +#include + +class NormalTextRender : public TextRender +{ + public: + + NormalTextRender(BFont f):TextRender(){ + font=f; + } + virtual ~NormalTextRender() {}; + + virtual void Render(BView *target,const char* txt,int16 num,BPoint pos) { + + target->SetFont(&font); + target->DrawString(txt,num,pos); + + + }; + + + virtual float Size(){ return font.Size();} + + virtual void GetHeight(font_height *height){ font.GetHeight(height); }; + + + virtual void + GetEscapements(const char charArray[], int32 numChars,float escapementArray[]) + { + font.GetEscapements(charArray,numChars,escapementArray); + } + + private: + BFont font; + +}; +#endif diff --git a/libs/librunview/ObjectList.h b/libs/librunview/ObjectList.h new file mode 100644 index 0000000..a4655d0 --- /dev/null +++ b/libs/librunview/ObjectList.h @@ -0,0 +1,866 @@ +/* +Open Tracker License + +Terms and Conditions + +Copyright (c) 1991-2000, Be Incorporated. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice applies to all licensees +and shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Be Incorporated shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization from Be Incorporated. + +Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks +of Be Incorporated in the United States and other countries. Other brand product +names are registered trademarks or trademarks of their respective holders. +All rights reserved. +*/ + +/**************************************************************************** +** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** +** ** +** DANGER, WILL ROBINSON! ** +** ** +** The interfaces contained here are part of BeOS's ** +** ** +** >> PRIVATE NOT FOR PUBLIC USE << ** +** ** +** implementation. ** +** ** +** These interfaces WILL CHANGE in future releases. ** +** If you use them, your app WILL BREAK at some future time. ** +** ** +** (And yes, this does mean that binaries built from OpenTracker will not ** +** be compatible with some future releases of the OS. When that happens, ** +** we will provide an updated version of this file to keep compatibility.) ** +** ** +** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** +****************************************************************************/ + +// +// ObjectList is a wrapper around BList that adds type safety, +// optional object ownership, search, insert operations, etc. +// + +#ifndef __OBJECT_LIST__ +#define __OBJECT_LIST__ + +#ifndef _BE_H +#include +#endif + +#include + + +template class BObjectList; + +template +struct UnaryPredicate { + + virtual int operator()(const T *) const + // virtual could be avoided here if FindBinaryInsertionIndex, + // etc. were member template functions + { return 0; } + +private: + static int _unary_predicate_glue(const void *item, void *context); + +friend class BObjectList; +}; + +template +int +UnaryPredicate::_unary_predicate_glue(const void *item, void *context) +{ + return ((UnaryPredicate *)context)->operator()((const T *)item); +} + + +class _PointerList_ : public BList { +public: + _PointerList_(const _PointerList_ &list); + _PointerList_(int32 itemsPerBlock = 20, bool owning = false); + ~_PointerList_(); + + typedef void *(* GenericEachFunction)(void *, void *); + typedef int (* GenericCompareFunction)(const void *, const void *); + typedef int (* GenericCompareFunctionWithState)(const void *, const void *, + void *); + typedef int (* UnaryPredicateGlue)(const void *, void *); + + void *EachElement(GenericEachFunction, void *); + void SortItems(GenericCompareFunction); + void SortItems(GenericCompareFunctionWithState, void *state); + void HSortItems(GenericCompareFunction); + void HSortItems(GenericCompareFunctionWithState, void *state); + + void *BinarySearch(const void *, GenericCompareFunction) const; + void *BinarySearch(const void *, GenericCompareFunctionWithState, void *state) const; + + int32 BinarySearchIndex(const void *, GenericCompareFunction) const; + int32 BinarySearchIndex(const void *, GenericCompareFunctionWithState, void *state) const; + int32 BinarySearchIndexByPredicate(const void *, UnaryPredicateGlue) const; + + bool Owning() const; + bool ReplaceItem(int32, void *); + +protected: + bool owning; + +}; + +template +class BObjectList : private _PointerList_ { +public: + + // iteration and sorting + typedef T *(* EachFunction)(T *, void *); + typedef const T *(* ConstEachFunction)(const T *, void *); + typedef int (* CompareFunction)(const T *, const T *); + typedef int (* CompareFunctionWithState)(const T *, const T *, void *state); + + BObjectList(int32 itemsPerBlock = 20, bool owning = false); + BObjectList(const BObjectList &list); + // clones list; if list is owning, makes copies of all + // the items + + virtual ~BObjectList(); + + BObjectList &operator=(const BObjectList &list); + // clones list; if list is owning, makes copies of all + // the items + + // adding and removing + // ToDo: + // change Add calls to return const item + bool AddItem(T *); + bool AddItem(T *, int32); + bool AddList(BObjectList *); + bool AddList(BObjectList *, int32); + + bool RemoveItem(T *, bool deleteIfOwning = true); + // if owning, deletes the removed item + T *RemoveItemAt(int32); + // returns the removed item + + void MakeEmpty(); + + // item access + T *ItemAt(int32) const; + + bool ReplaceItem(int32 index, T *); + // if list is owning, deletes the item at first + T *SwapWithItem(int32 index, T *newItem); + // same as ReplaceItem, except does not delete old item at , + // returns it instead + + T *FirstItem() const; + T *LastItem() const; + + // misc. getters + int32 IndexOf(const T *) const; + bool HasItem(const T *) const; + bool IsEmpty() const; + int32 CountItems() const; + + T *EachElement(EachFunction, void *); + const T *EachElement(ConstEachFunction, void *) const; + + void SortItems(CompareFunction); + void SortItems(CompareFunctionWithState, void *state); + void HSortItems(CompareFunction); + void HSortItems(CompareFunctionWithState, void *state); + + // linear search, returns first item that matches predicate + const T *FindIf(const UnaryPredicate &) const; + T *FindIf(const UnaryPredicate &); + + // list must be sorted with CompareFunction for these to work + T *BinarySearch(const T &, CompareFunction) const; + T *BinarySearch(const T &, CompareFunctionWithState, void *state) const; + + template + T *BinarySearchByKey(const Key &key, int (*compare)(const Key *, const T *)) + const; + + template + T *BinarySearchByKey(const Key &key, + int (*compare)(const Key *, const T *, void *), void *state) const; + + int32 BinarySearchIndex(const T &item, CompareFunction compare) const; + int32 BinarySearchIndex(const T &item, CompareFunctionWithState compare, + void *state) const; + + template + int32 BinarySearchIndexByKey(const Key &key, + int (*compare)(const Key *, const T *)) const; + + // Binary insertion - list must be sorted with CompareFunction for + // these to work + + // simple insert + bool BinaryInsert(T *, CompareFunction); + bool BinaryInsert(T *, CompareFunctionWithState, void *state); + bool BinaryInsert(T *, const UnaryPredicate &); + + // unique insert, returns false if item already in list + bool BinaryInsertUnique(T *, CompareFunction); + bool BinaryInsertUnique(T *, CompareFunctionWithState, void *state); + bool BinaryInsertUnique(T *, const UnaryPredicate &); + + // insert a copy of the item, returns new inserted item + T *BinaryInsertCopy(const T ©This, CompareFunction); + T *BinaryInsertCopy(const T ©This, CompareFunctionWithState, void *state); + + // insert a copy of the item if not in list already + // returns new inserted item or existing item in case of a conflict + T *BinaryInsertCopyUnique(const T ©This, CompareFunction); + T *BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState, void *state); + + int32 FindBinaryInsertionIndex(const UnaryPredicate &, bool *alreadyInList = 0) const; + // returns either the index into which a new item should be inserted + // or index of an existing item that matches the predicate + + // deprecated API, will go away + BList *AsBList() + { return this; } + const BList *AsBList() const + { return this; } +private: + void SetItem(int32, T *); +}; + +template +Result +WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1), Param1 p1) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (list->ItemAt(index)->*func)(p1)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1), Param1 p1) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1, Param2), + Param1 p1, Param2 p2) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (list->ItemAt(index)->*func)(p1, p2)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2), + Param1 p1, Param2 p2) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1, p2)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2, + Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1, p2, p3, p4)) != 0) + break; + + return result; +} + +template +void +EachListItemIgnoreResult(BObjectList *list, Result (Item::*func)()) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (list->ItemAt(index)->*func)(); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *, Param1), Param1 p1) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1); +} + +template +void +EachListItem(BObjectList *list, void (Item::*func)(Param1, Param2), + Param1 p1, Param2 p2) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (list->ItemAt(index)->*func)(p1, p2); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2), + Param1 p1, Param2 p2) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, + Param3), Param1 p1, Param2 p2, Param3 p3) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2, p3); +} + + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, + Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2, p3, p4); +} + +// inline code + +inline bool +_PointerList_::Owning() const +{ + return owning; +} + +template +BObjectList::BObjectList(int32 itemsPerBlock, bool owning) + : _PointerList_(itemsPerBlock, owning) +{ +} + +template +BObjectList::BObjectList(const BObjectList &list) + : _PointerList_(list) +{ + owning = list.owning; + if (owning) { + // make our own copies in an owning list + int32 count = list.CountItems(); + for (int32 index = 0; index < count; index++) { + T *item = list.ItemAt(index); + if (item) + item = new T(*item); + SetItem(index, item); + } + } +} + +template +BObjectList::~BObjectList() +{ + if (Owning()) + // have to nuke elements first + MakeEmpty(); +} + +template +BObjectList & +BObjectList::operator=(const BObjectList &list) +{ + owning = list.owning; + BObjectList &result = (BObjectList &)_PointerList_::operator=(list); + if (owning) { + // make our own copies in an owning list + int32 count = list.CountItems(); + for (int32 index = 0; index < count; index++) { + T *item = list.ItemAt(index); + if (item) + item = new T(*item); + SetItem(index, item); + } + } + return result; +} + +template +bool +BObjectList::AddItem(T *item) +{ + // need to cast to void * to make T work for const pointers + return _PointerList_::AddItem((void *)item); +} + +template +bool +BObjectList::AddItem(T *item, int32 atIndex) +{ + return _PointerList_::AddItem((void *)item, atIndex); +} + +template +bool +BObjectList::AddList(BObjectList *newItems) +{ + return _PointerList_::AddList(newItems); +} + +template +bool +BObjectList::AddList(BObjectList *newItems, int32 atIndex) +{ + return _PointerList_::AddList(newItems, atIndex); +} + + +template +bool +BObjectList::RemoveItem(T *item, bool deleteIfOwning) +{ + bool result = _PointerList_::RemoveItem((void *)item); + + if (result && Owning() && deleteIfOwning) + delete item; + + return result; +} + +template +T * +BObjectList::RemoveItemAt(int32 index) +{ + return (T *)_PointerList_::RemoveItem(index); +} + +template +inline T * +BObjectList::ItemAt(int32 index) const +{ + return (T *)_PointerList_::ItemAt(index); +} + +template +bool +BObjectList::ReplaceItem(int32 index, T *item) +{ + if (owning) + delete ItemAt(index); + return _PointerList_::ReplaceItem(index, (void *)item); +} + +template +T * +BObjectList::SwapWithItem(int32 index, T *newItem) +{ + T *result = ItemAt(index); + _PointerList_::ReplaceItem(index, (void *)newItem); + return result; +} + +template +void +BObjectList::SetItem(int32 index, T *newItem) +{ + _PointerList_::ReplaceItem(index, (void *)newItem); +} + +template +int32 +BObjectList::IndexOf(const T *item) const +{ + return _PointerList_::IndexOf((void *)item); +} + +template +T * +BObjectList::FirstItem() const +{ + return (T *)_PointerList_::FirstItem(); +} + +template +T * +BObjectList::LastItem() const +{ + return (T *)_PointerList_::LastItem(); +} + +template +bool +BObjectList::HasItem(const T *item) const +{ + return _PointerList_::HasItem((void *)item); +} + +template +bool +BObjectList::IsEmpty() const +{ + return _PointerList_::IsEmpty(); +} + +template +int32 +BObjectList::CountItems() const +{ + return _PointerList_::CountItems(); +} + +template +void +BObjectList::MakeEmpty() +{ + if (owning) { + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + delete ItemAt(index); + } + _PointerList_::MakeEmpty(); +} + +template +T * +BObjectList::EachElement(EachFunction func, void *params) +{ + return (T *)_PointerList_::EachElement((GenericEachFunction)func, params); +} + + +template +const T * +BObjectList::EachElement(ConstEachFunction func, void *params) const +{ + return (const T *) + const_cast *>(this)->_PointerList_::EachElement( + (GenericEachFunction)func, params); +} + +template +const T * +BObjectList::FindIf(const UnaryPredicate &predicate) const +{ + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + if (predicate.operator()(ItemAt(index)) == 0) + return ItemAt(index); + return 0; +} + +template +T * +BObjectList::FindIf(const UnaryPredicate &predicate) +{ + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + if (predicate.operator()(ItemAt(index)) == 0) + return ItemAt(index); + return 0; +} + + +template +void +BObjectList::SortItems(CompareFunction function) +{ + _PointerList_::SortItems((GenericCompareFunction)function); +} + +template +void +BObjectList::SortItems(CompareFunctionWithState function, void *state) +{ + _PointerList_::SortItems((GenericCompareFunctionWithState)function, state); +} + +template +void +BObjectList::HSortItems(CompareFunction function) +{ + _PointerList_::HSortItems((GenericCompareFunction)function); +} + +template +void +BObjectList::HSortItems(CompareFunctionWithState function, void *state) +{ + _PointerList_::HSortItems((GenericCompareFunctionWithState)function, state); +} + +template +T * +BObjectList::BinarySearch(const T &key, CompareFunction func) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunction)func); +} + +template +T * +BObjectList::BinarySearch(const T &key, CompareFunctionWithState func, void *state) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunctionWithState)func, state); +} + + +template +template +T * +BObjectList::BinarySearchByKey(const Key &key, + int (*compare)(const Key *, const T *)) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunction)compare); +} + + +template +template +T * +BObjectList::BinarySearchByKey(const Key &key, + int (*compare)(const Key *, const T *, void *), void *state) const +{ + return (T*)_PointerList_::BinarySearch(&key, + (GenericCompareFunctionWithState)compare, state); +} + + +template +int32 +BObjectList::BinarySearchIndex(const T &item, CompareFunction compare) const +{ + return _PointerList_::BinarySearchIndex(&item, + (GenericCompareFunction)compare); +} + + +template +int32 +BObjectList::BinarySearchIndex(const T &item, + CompareFunctionWithState compare, void *state) const +{ + return _PointerList_::BinarySearchIndex(&item, + (GenericCompareFunctionWithState)compare, state); +} + + +template +template +int32 +BObjectList::BinarySearchIndexByKey(const Key &key, + int (*compare)(const Key *, const T *)) const +{ + return _PointerList_::BinarySearchIndex(&key, + (GenericCompareFunction)compare); +} + + +template +bool +BObjectList::BinaryInsert(T *item, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunction)func); + if (index >= 0) { + // already in list, add after existing + return AddItem(item, index + 1); + } + + return AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsert(T *item, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) { + // already in list, add after existing + return AddItem(item, index + 1); + } + + return AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunction)func); + if (index >= 0) + return false; + + return AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + return false; + + return AddItem(item, -index - 1); +} + + +template +T * +BObjectList::BinaryInsertCopy(const T ©This, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunction)func); + + if (index >= 0) + index++; + else + index = -index - 1; + + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopy(const T ©This, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunctionWithState)func, state); + + if (index >= 0) + index++; + else + index = -index - 1; + + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunction)func); + if (index >= 0) + return ItemAt(index); + + index = -index - 1; + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState func, + void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + return ItemAt(index); + + index = -index - 1; + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +int32 +BObjectList::FindBinaryInsertionIndex(const UnaryPredicate &pred, bool *alreadyInList) + const +{ + int32 index = _PointerList_::BinarySearchIndexByPredicate(&pred, + (UnaryPredicateGlue)&UnaryPredicate::_unary_predicate_glue); + + if (alreadyInList) + *alreadyInList = index >= 0; + + if (index < 0) + index = -index - 1; + + return index; +} + +template +bool +BObjectList::BinaryInsert(T *item, const UnaryPredicate &pred) +{ + return AddItem(item, FindBinaryInsertionIndex(pred)); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, const UnaryPredicate &pred) +{ + bool alreadyInList; + int32 index = FindBinaryInsertionIndex(pred, &alreadyInList); + if (alreadyInList) + return false; + + AddItem(item, index); + return true; +} + +#endif /* __OBJECT_LIST__ */ diff --git a/libs/librunview/RunView.cpp b/libs/librunview/RunView.cpp new file mode 100644 index 0000000..f93e51c --- /dev/null +++ b/libs/librunview/RunView.cpp @@ -0,0 +1,2622 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Rene Gollent + * Todd Lair + * Alan Ellis + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#define FORE_WHICH 0 +#define BACK_WHICH 1 +#define FONT_WHICH 2 + +#define OFFVIEW_TIMER (10000LL) +#define ABS(x) (x * ((x<0) ? -1 : 1)) +#define SOFTBREAK_STEP 5 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ObjectList.h" +#include "Theme.h" +#include "RunView.h" +#include "URLCrunch.h" +#include "Utilities.h" + +#include +#include + +#ifdef ZETA +#include +#else +#define _T(str) (str) +#endif + +// cursor data for hovering over URLs + +static unsigned char URLCursorData[] = {16,1,2,2, + 0,0,0,0,56,0,36,0,36,0,19,224,18,92,9,42, + 8,1,60,33,76,49,66,121,48,125,12,253,2,0,1,0, + 0,0,0,0,56,0,60,0,60,0,31,224,31,252,15,254, + 15,255,63,255,127,255,127,255,63,255,15,255,3,254,1,248 +}; + +struct SoftBreak +{ + int16 fOffset; + float fHeight; + float fAscent; +}; + +struct URL +{ + int32 fOffset; + int32 fLength; + BString fUrl; + + URL (const char *address, int32 off, int32 len) : + fOffset (off), + fLength (len), + fUrl (address) + { } +}; + +typedef BObjectList urllist; + +struct SoftBreakEnd +{ + int16 fOffset; + + SoftBreakEnd (int16 offset) + : fOffset (offset) + { } +}; + +struct FontColor +{ + int16 fOffset; + // G++ is stupid. We only need 2 bits + // for fWhich, but the compiler has a bug + // and warns us against fWhich == 2 + int16 fWhich : 3; + int16 fIndex : 13; +}; + +struct Line +{ + char *fText; + time_t fStamp; + urllist *fUrls; + int16 *fSpaces; + int16 *fEdges; + FontColor *fFcs; + SoftBreak *fSofties; + float fTop; + float fBottom; + + int16 fLength; + int16 fSpace_count; + int16 fEdge_count; + int16 fFc_count; + int16 fSoftie_size; + int16 fSoftie_used; + + Line ( + const char *buffer, + int16 fLength, + float top, + float width, + Theme *fTheme, + const char *fStamp_format, + int16 fore, + int16 back, + int16 font); + + ~Line (void); + + void Append ( + const char *buffer, + int16 len, + float width, + Theme *fTheme, + int16 fore, + int16 back, + int16 font); + + void FigureSpaces (void); + + void FigureFontColors ( + int16 pos, + int16 fore, + int16 back, + int16 font); + + void FigureEdges ( + Theme *fTheme, + float width); + + void SoftBreaks ( + Theme * fTheme, + float width); + + void AddSoftBreak (SoftBreakEnd , float &, + uint16 &, int16 &, float &, float &, Theme *); + + int16 CountChars (int16 pos, int16 len); + size_t SetStamp (const char *, bool); + + void SelectWord (int16 *, int16 *); +}; + +inline int32 +UTF8_CHAR_LEN (uchar c) +{ + return (((0xE5000000 >> (((c) >> 3) & 0x1E)) & 3) + 1); +} + +RunView::RunView ( + BRect frame, + const char *name, + Theme *theme, + uint32 resizingMode, + uint32 flags) + : BView ( + frame, + name, + resizingMode, + flags | B_WILL_DRAW | B_FRAME_EVENTS), + fScroller (NULL), + fTheme (theme), + fWorking (NULL), + fLine_count (0), + fStamp_format (NULL), + fClipping_name (NULL), + fSp_start (0, 0), + fSp_end (0, 0), + fTracking (0), + fTrack_offset (0, 0), + fOff_view_runner (NULL), + fOff_view_time (0), + fResizedirty (false), + fFontsdirty (false), + fMyPopUp (NULL), + fLastClick (0,0), + fLastClickTime (0) +{ + + memset (fLines, 0, sizeof (fLines)); + fURLCursor = new BCursor (URLCursorData); + + fTheme->ReadLock(); + BView::SetViewColor (B_TRANSPARENT_COLOR); + BView::SetLowColor (fTheme->BackgroundAt (Theme::NormalBack)); + BView::SetHighColor (fTheme->ForegroundAt (Theme::NormalFore)); + fTheme->ReadUnlock(); +} + + +RunView::~RunView (void) +{ + for (int16 i = 0; i < fLine_count; ++i) + delete fLines[i]; + + delete fWorking; + delete fURLCursor; + delete [] fStamp_format; + delete [] fClipping_name; +} + +void +RunView::AttachedToWindow (void) +{ + BView::AttachedToWindow(); +#if B_BEOS_VERSION_DANO + SetDoubleBuffering (B_UPDATE_INVALIDATED | B_UPDATE_SCROLLED | B_UPDATE_EXPOSED | B_UPDATE_RESIZED); +#endif + RecalcScrollBar (false); + fTheme->WriteLock(); + fTheme->AddView (this); + fTheme->WriteUnlock(); +} + +void +RunView::DetachedFromWindow (void) +{ + fTheme->WriteLock(); + fTheme->RemoveView (this); + fTheme->WriteUnlock(); +} + +void +RunView::FrameResized (float start_width, float height) +{ + BView::FrameResized (start_width, height); + + if (IsHidden()) + { + fResizedirty = true; + return; + } + ResizeRecalc(); +} + +void +RunView::TargetedByScrollView (BScrollView *s) +{ + fScroller = s; + BView::TargetedByScrollView (fScroller); +} + +void +RunView::Show (void) +{ + if (fFontsdirty) + { + FontChangeRecalc(); + // this effectively does the same thing as resize so if both have changed, only + // do the fonts recalculation + fFontsdirty = false; + fResizedirty = false; + } + else if (fResizedirty) + { + ResizeRecalc(); + fResizedirty = false; + } + BView::Show(); +} + +void +RunView::Draw (BRect frame) +{ + TextRender *tr = NULL; + + Window()->DisableUpdates(); + Window()->BeginViewTransaction(); + + rgb_color low_color, hi_color, view_color, sel_color, sel_fText; + float height (frame.bottom); + BRect bounds (Bounds()); + BRegion clipper; + bool drawSelection (false); + bool checkSelection (fSp_start != fSp_end); + + clipper.Set (frame); + ConstrainClippingRegion (&clipper); + + fTheme->ReadLock(); + view_color = fTheme->BackgroundAt (Theme::NormalBack); + + sel_color = fTheme->BackgroundAt (Theme::SelectionBack); + if (((sel_color.red + sel_color.blue + sel_color.green) / 3) >= 127) + { + sel_fText.red = sel_fText.green = sel_fText.blue = 0; + sel_fText.alpha = 255; + } + else + { + sel_fText.red = sel_fText.green = sel_fText.blue = sel_fText.alpha = 255; + } + BRect remains; + if (fLine_count == 0) + remains = frame; + else if (frame.bottom >= fLines[fLine_count - 1]->fBottom + 1.0) + remains.Set ( + frame.left, + fLines[fLine_count - 1]->fBottom + 1.0, + frame.right, + frame.bottom); + + if (remains.IsValid()) + { + SetLowColor (view_color); + FillRect (remains, B_SOLID_LOW); + } + + for (int16 i = fLine_count - 1; i >= 0; --i) + { + Line *line (fLines[i]); + if (line->fBottom < frame.top) + break; + + BRect r (bounds.left, line->fTop, bounds.right, line->fBottom); + + if (!frame.Intersects (r)) + continue; + + float indent (fTheme->TextMargin()); + int16 place (0); + + int16 fore (0); + int16 back (0); + int16 font (0); + + height = line->fTop; + + for (int16 sit = 0; sit < line->fSoftie_used; /*++sit*/sit++) + { + int16 last_len (UTF8_CHAR_LEN (line->fText[line->fSofties[sit].fOffset])); + float left (indent); + float start (0.0); + + // Fill indentation + SetLowColor (view_color); + + SetDrawingMode (B_OP_COPY); + r.Set (0.0, height, indent - 1.0, height + line->fSofties[sit].fHeight - 1.0); + FillRect (r, B_SOLID_LOW); + + if (sit) + { + int16 j (place); + + while (--j >= 0) + if ((start = line->fEdges[j]) != 0) + break; + } + + while (place < line->fSofties[sit].fOffset + last_len) + { + // Get current foreground color and set + while (fore < line->fFc_count) + { + if (line->fFcs[fore].fWhich == FORE_WHICH) + { + if (line->fFcs[fore].fOffset > place) + break; + + hi_color = fTheme->ForegroundAt (line->fFcs[fore].fIndex); + } + + ++fore; + } + + // Get current background color and set + while (back < line->fFc_count) + { + if (line->fFcs[back].fWhich == BACK_WHICH) + { + if (line->fFcs[back].fOffset > place) + break; + + + low_color = fTheme->BackgroundAt (line->fFcs[back].fIndex); + } + + ++back; + } + + // Get current font and set + while (font < line->fFc_count) + { + if (line->fFcs[font].fWhich == FONT_WHICH) + { + if (line->fFcs[font].fOffset > place) + break; + + //const BFont &f (fTheme->FontAt (line->fFcs[font].fIndex)); + tr = fTheme->TextRenderAt (line->fFcs[font].fIndex); + //SetFont (&f); + } + + ++font; + } + + int16 fLength (line->fSofties[sit].fOffset - place + last_len); + + if (fore < line->fFc_count + && line->fFcs[fore].fOffset - place < fLength) + fLength = line->fFcs[fore].fOffset - place; + + if (back < line->fFc_count + && line->fFcs[back].fOffset - place < fLength) + fLength = line->fFcs[back].fOffset - place; + + if (font < line->fFc_count + && line->fFcs[font].fOffset - place < fLength) + fLength = line->fFcs[font].fOffset - place; + + if (checkSelection) + { + // case 1: current line marks beginning of selection + if (i == fSp_start.fLine) + { + // if we're just prior to the selection, clip fLength to only + // draw up to the selection start + if (place + fLength >= fSp_start.fOffset && place < fSp_start.fOffset) + { + fLength = fSp_start.fOffset - place; + drawSelection = false; + } + // we're at the selection, switch drawing color mode + else if (place >= fSp_start.fOffset) + { + if (fSp_end.fLine == fSp_start.fLine) + { + if (place < fSp_end.fOffset) + { + drawSelection = true; + if ((fSp_end.fOffset - place) < fLength) + fLength = fSp_end.fOffset - place; + } + else + drawSelection = false; + } + else + drawSelection = true; + } + else + drawSelection = false; + + } + // case 2: line in between beginning and end of selection, + // highlight entire line + else if (i > fSp_start.fLine && i < fSp_end.fLine) + drawSelection = true; + // case 3: last line of selection, with multiple fLines in between + else if (i == fSp_end.fLine && i != fSp_start.fLine) + { + if (place < (fSp_end.fOffset)) + { + if (fSp_end.fOffset - place < fLength) + fLength = (fSp_end.fOffset - place); + drawSelection = true; + } + else + drawSelection = false; + } + else + drawSelection = false; + } + + if (place + fLength == line->fLength) + --fLength; + + int16 k (place + fLength - 1); + while (line->fEdges[k] == 0) + --k; + + r.Set ( + left, + height, + line->fEdges[k] + indent - start, + height + line->fSofties[sit].fHeight - 1.0); + + SetDrawingMode (B_OP_COPY); + if (drawSelection) + SetLowColor (sel_color); + else + SetLowColor (low_color); + SetHighColor (hi_color); + FillRect (r, B_SOLID_LOW); + + if (drawSelection) + SetHighColor (sel_fText); + + SetDrawingMode (B_OP_OVER); + + if ( sit >= line->fSoftie_used ) + { + printf("bah. sit is %d and fSoftie_used is %d\n", sit, line->fSoftie_used); + } else { + + tr->Render(this, + line->fText + place, + min_c (fLength, line->fLength - place - 1), + BPoint (left, height + line->fSofties[sit].fAscent)); + } + + left = line->fEdges[k] + indent - start; + + if ((place += fLength) + 1 >= line->fLength) + ++place; + } + + + // Margin after fText + SetDrawingMode (B_OP_COPY); + SetLowColor (view_color); + FillRect ( + BRect ( + left + 1.0, + height, + bounds.right, + height + line->fSofties[sit].fHeight - 1.0), + B_SOLID_LOW); + + height += line->fSofties[sit].fHeight; + + if (sit == 0) + indent += fTheme->SoftLineIndent();//fSoftLineIndent; + } + } + + fTheme->ReadUnlock(); + Window()->EndViewTransaction(); + Window()->EnableUpdates(); + ConstrainClippingRegion (NULL); +} + +void +RunView::SetViewColor (rgb_color color) +{ + assert (memcmp (&color, &B_TRANSPARENT_COLOR, sizeof (rgb_color)) != 0); + BView::SetViewColor (color); +} + +void +RunView::BuildPopUp (void) +{ + // This function checks certain criteria (fText is selected, + // TextView is editable, etc) to determine fWhich MenuItems + // to enable and disable + + bool enablecopy (true), + enableselectall (true), + enablelookup (false); + BString querystring (""); + + if (fSp_start == fSp_end) + enablecopy = false; // no selection + + if (!fLine_count) + enableselectall = false; + + if (enablecopy) + { + enablelookup = true; // has a selection less than 32 chars long + GetSelectionText(querystring); + } + + fMyPopUp = new BPopUpMenu ("IRCView Context Menu", false, false); + + BMenuItem *item; + + BMessage *lookup; + lookup = new BMessage (M_LOOKUP_WEBSTER); + lookup->AddString ("string", querystring); + item = new BMenuItem(_T("Lookup (Dictionary)"), lookup); + item->SetEnabled (enablelookup); + item->SetTarget(this); + fMyPopUp->AddItem (item); + + lookup = new BMessage (M_LOOKUP_GOOGLE); + lookup->AddString ("string", querystring); + item = new BMenuItem(_T("Lookup (Google)"), lookup); + item->SetEnabled (enablelookup); + item->SetTarget(this); + fMyPopUp->AddItem (item); + + lookup = new BMessage (M_LOOKUP_ACRONYM); + lookup->AddString ("string", querystring); + item = new BMenuItem(_T("Lookup (Acronym Finder)"), lookup); + item->SetEnabled (enablelookup); + item->SetTarget(this); + fMyPopUp->AddItem (item); + + fMyPopUp->AddSeparatorItem(); + + item = new BMenuItem(_T("Copy"), new BMessage (B_COPY), 'C'); + item->SetEnabled (enablecopy); + item->SetTarget (this); + fMyPopUp->AddItem (item); + + item = new BMenuItem(_T("Select All"), new BMessage (B_SELECT_ALL), 'A'); + item->SetEnabled (enableselectall); + item->SetTarget (this); + fMyPopUp->AddItem (item); + + fMyPopUp->AddSeparatorItem(); + + item = new BMenuItem(_T("Clear"), new BMessage(M_CLEAR)); + item->SetTarget(this); + fMyPopUp->AddItem(item); + + fMyPopUp->SetFont (be_plain_font); +} + +bool +RunView::CheckClickBounds (const SelectPos &s, const BPoint &point) const +{ + return ((point.x <= fLines[s.fLine]->fEdges[fLines[s.fLine]->fLength - 1]) + && (point.y <= fLines[s.fLine]->fBottom)); +} + +void +RunView::MouseDown (BPoint point) +{ + if (!fLine_count) + return; + + BMessage *msg (Window()->CurrentMessage()); + uint32 buttons; + uint32 mouseModifiers; + bigtime_t sysTime; + msg->FindInt64 ("when", &sysTime); + uint16 clicks = CheckClickCount (point, fLastClick, sysTime, fLastClickTime, fClickCount) % 3; + msg->FindInt32 ("buttons", reinterpret_cast(&buttons)); + msg->FindInt32 ("modifiers", reinterpret_cast(&mouseModifiers)); + + SelectPos s (PositionAt (point)); + bool inBounds (CheckClickBounds (s, point)); + + if (buttons == B_SECONDARY_MOUSE_BUTTON + && (mouseModifiers & B_SHIFT_KEY) == 0 + && (mouseModifiers & B_COMMAND_KEY) == 0 + && (mouseModifiers & B_CONTROL_KEY) == 0 + && (mouseModifiers & B_OPTION_KEY) == 0 + && (mouseModifiers & B_MENU_KEY) == 0) + { + SelectPos start (s), + end (s); + + // select word + if (inBounds && !IntersectSelection (s,s)) + { + fLines[s.fLine]->SelectWord (&start.fOffset, &end.fOffset); + + Select (start, end); + } + + BuildPopUp(); + fMyPopUp->Go ( + ConvertToScreen (point), + true, + false); + + delete fMyPopUp; + fMyPopUp = 0; + return; + } + + if (buttons == B_PRIMARY_MOUSE_BUTTON + && (mouseModifiers & B_SHIFT_KEY) == 0 + && (mouseModifiers & B_COMMAND_KEY) == 0 + && (mouseModifiers & B_CONTROL_KEY) == 0 + && (mouseModifiers & B_OPTION_KEY) == 0 + && (mouseModifiers & B_MENU_KEY) == 0) + { + SelectPos start (s), + end (s); + + switch (clicks) + { + case 2: + { + if (inBounds) + { + // select word + fLines[s.fLine]->SelectWord (&start.fOffset, &end.fOffset); + + Select (start, end); + return; + } + } + break; + + case 0: + { + if (inBounds) + { + start.fOffset = 0; + end.fOffset = fLines[s.fLine]->fLength - 1; + Select (start, end); + return; + } + } + break; + + default: + { + if (!inBounds || !IntersectSelection (s, s)) + Select (s,s); + SetMouseEventMask (B_POINTER_EVENTS); + fTracking = 1; + fTrack_offset = s; + return; + } + } + } + else if (buttons == B_PRIMARY_MOUSE_BUTTON + && (mouseModifiers & B_SHIFT_KEY) != 0 + && (mouseModifiers & B_COMMAND_KEY) == 0 + && (mouseModifiers & B_CONTROL_KEY) == 0 + && (mouseModifiers & B_OPTION_KEY) == 0 + && (mouseModifiers & B_MENU_KEY) == 0) + { + if (s.fLine < fSp_start.fLine || s.fOffset < fSp_start.fOffset) + { + Select (s, fSp_end); + fTrack_offset = SelectPos (fSp_end.fLine, (fSp_end.fOffset > 0) ? fSp_end.fOffset - 1 : fSp_end.fOffset); + } + else + { + Select (fSp_start, s); + fTrack_offset = fSp_start; + } + + SetMouseEventMask (B_POINTER_EVENTS); + fTracking = 2; + } +} + +void +RunView::CheckURLCursor (BPoint point) +{ + if (!fLine_count) + return; + + SelectPos s = PositionAt (point); + + if (!fLines[s.fLine]->fUrls) + { + // if there aren't any URLs in the current line, go back to default + SetViewCursor (B_CURSOR_SYSTEM_DEFAULT); + return; + } + Line *curline (fLines[s.fLine]); + + for (int32 i = 0; i < curline->fUrls->CountItems(); i++) + { + URL *current = curline->fUrls->ItemAt(i); + if ((s.fOffset >= current->fOffset) + && (s.fOffset <= current->fOffset + current->fLength)) + { + SetViewCursor (fURLCursor); + return; + } + } + + // no URLs found, set back to default + SetViewCursor (B_CURSOR_SYSTEM_DEFAULT); +} + +void +RunView::MouseMoved (BPoint point, uint32 transit, const BMessage *msg) +{ + if (fTracking == 0 + && fLine_count + && (transit == B_ENTERED_VIEW + || transit == B_INSIDE_VIEW)) + CheckURLCursor (point); + + + if (!fLine_count || fTracking == 0) + { + BView::MouseMoved (point, transit, msg); + return; + } + + switch (transit) + { + case B_ENTERED_VIEW: + if (fOff_view_runner) + { + delete fOff_view_runner; + fOff_view_runner = 0; + } + + if (fTracking == 1 || fTracking == 2) + ExtendTrackingSelect (point); + + break; + + case B_EXITED_VIEW: + if (fTracking == 1 || fTracking == 2) + ShiftTrackingSelect (point, true, OFFVIEW_TIMER); + break; + + case B_OUTSIDE_VIEW: + + if (fTracking == 1 || fTracking == 2) + { + bigtime_t now (system_time()); + + ShiftTrackingSelect ( + point, + false, + max_c (0LL, min_c (OFFVIEW_TIMER, OFFVIEW_TIMER - (now - fOff_view_time)))); + } + break; + + case B_INSIDE_VIEW: + + if ((fTracking == 1) && (fSp_start != fSp_end)) + { + BMessage msg (B_MIME_DATA); + BString fText; + + GetSelectionText (fText); + msg.AddData ( + "text/plain", + B_MIME_TYPE, + fText.String(), + fText.Length() + 1); + + BString clip_name (" Clipping"); + + if (fClipping_name) + clip_name.Prepend (fClipping_name); + else + clip_name.Prepend ("RunView"); + + msg.AddString ("be:clip_name", clip_name.String()); + msg.AddInt32 ("be:actions", B_COPY_TARGET); + + BRect frame ( + fLines[fSp_start.fLine]->fEdges[fSp_start.fOffset], + fLines[fSp_start.fLine]->fTop, + fLines[fSp_end.fLine]->fEdges[fSp_end.fOffset], + fLines[fSp_end.fLine]->fBottom); + + if (fSp_start.fLine != fSp_end.fLine) + { + frame.left = 0.0; + frame.right = Bounds().right; + } + // selection lies within the bounds of a line, check + // if it fLines on one of the wrapped subfLines and calculate rectangle + // appropriately + else + { + Line *line (fLines[fSp_start.fLine]); + float left (line->fEdges[fSp_start.fOffset]), + top (line->fTop), + right (line->fEdges[fSp_end.fOffset]), + bottom (line->fBottom); + int top_softie (0), bottom_softie (0); + bool start_found (false); + bool end_found (false); + + if (line->fSoftie_used) + { + if (fSp_start.fOffset < line->fSofties[0].fOffset) + start_found = true; + + if (fSp_end.fOffset < line->fSofties[0].fOffset) + end_found = true; + } + + if (!end_found) + for (int16 sit = 1; sit < line->fSoftie_used; ++sit) + { + if (!start_found && fSp_start.fOffset < line->fSofties[sit].fOffset) + { + left = line->fEdges[fSp_start.fOffset] - + line->fEdges[line->fSofties[sit-1].fOffset]; + + top += (sit) * line->fSofties[sit].fHeight; + top_softie = sit; + start_found = true; + } + + if (fSp_end.fOffset < line->fSofties[sit].fOffset) + { + right = line->fEdges[fSp_end.fOffset] - + line->fEdges[line->fSofties[sit-1].fOffset]; + + bottom = top + (sit - top_softie + 1) * line->fSofties[sit].fHeight; + bottom_softie = sit; + end_found = true; + break; + } + } + if (!end_found) + { + int32 soft_count = (line->fSoftie_used >= 2) ? + line->fSoftie_used - 2 : 0; + right = line->fEdges[line->fLength - 1] - + line->fEdges[line->fSofties[soft_count].fOffset]; + bottom_softie = soft_count - 2; + + } + if (right < left || (bottom_softie - top_softie) > 0) + { + left = 0.0; + right = Bounds().right; + } + + frame.Set (left, top, right, bottom); + frame.OffsetBy (fTheme->TextMargin(), 0.0); + } + + if (frame.Height() > Bounds().Height()) + frame = Bounds(); + + DragMessage (&msg, frame); + + fTracking = 3; + } + else if (fTracking == 1 || fTracking == 2) + ExtendTrackingSelect (point); + break; + } +} + +void +RunView::MouseUp (BPoint point) +{ + SelectPos s (PositionAt (point)); + bool url_handle (false); + + if (!fLine_count) + { + fTracking = 0; + return; + } + + if (fTracking == 1) + { + Line *curline (fLines[s.fLine]); + if (curline->fUrls) + { + for (int32 i = 0; i < curline->fUrls->CountItems(); i++) + { + URL *current = curline->fUrls->ItemAt(i); + if ((s.fOffset >= current->fOffset) + && (s.fOffset <= current->fOffset + current->fLength)) + { + + LoadURL (current->fUrl.String()); + url_handle = true; + break; + } + } + } + if (!url_handle && s == fTrack_offset) + Select (s, s); + } + + if (fOff_view_runner) + { + delete fOff_view_runner; + fOff_view_runner = 0; + } + + fTracking = 0; + +} + +void +RunView::ExtendTrackingSelect (BPoint point) +{ + SelectPos s (PositionAt (point)); + + if (s.fLine < fTrack_offset.fLine || (s.fLine == fTrack_offset.fLine && s.fOffset < fTrack_offset.fOffset)) + { + Select (s, fTrack_offset); + fTracking = 2; + } + else if (s.fLine > fTrack_offset.fLine || (s.fLine == fTrack_offset.fLine && s.fOffset > fTrack_offset.fOffset)) + { + Select (fTrack_offset, s); + fTracking = 2; + } +} + +void +RunView::ShiftTrackingSelect (BPoint point, bool move, bigtime_t timer) +{ + BRect bounds (Bounds()); + + if (fOff_view_runner) + { + delete fOff_view_runner; + fOff_view_runner = 0; + } + + if (point.y < bounds.top) + { + if (bounds.top > 0.0) + { + float delta (bounds.top - point.y); + + if (fOff_view_runner == 0) + { + BMessage *msg (new BMessage (M_OFFVIEW_SELECTION)); + + msg->AddFloat ("delta", delta); + msg->AddBool ("bottom", false); + msg->AddPoint ("point", point); + + fOff_view_runner = new BMessageRunner ( + BMessenger (this), + msg, + timer == 0LL ? OFFVIEW_TIMER : timer); + + } + + if (move || timer == 0) + { + delta = max_c (ABS (ceil (delta / 2.0)), 10.0); + delta = min_c (delta, Bounds().Height()); + + if (bounds.top - delta < 0.0) + delta = bounds.top; + + ScrollBy (0.0, -delta); + fOff_view_time = system_time(); + } + } + + point.x = 0.0; + point.y = Bounds().top; + ExtendTrackingSelect (point); + } + + if (point.y > bounds.bottom) + { + Line *line (fLines[fLine_count-1]); + if (line + && line->fBottom > bounds.bottom) + { + float delta (point.y - bounds.bottom); + + if (fOff_view_runner == 0) + { + BMessage *msg (new BMessage (M_OFFVIEW_SELECTION)); + + msg->AddFloat ("delta", delta); + msg->AddBool ("bottom", true); + msg->AddPoint ("point", point); + + fOff_view_runner = new BMessageRunner ( + BMessenger (this), + msg, + timer == 0LL ? OFFVIEW_TIMER : timer); + + } + + if (move || timer == 0) + { + delta = max_c (ABS (ceil (delta / 2.0)), 10.0); + delta = min_c (delta, Bounds().Height()); + + if (bounds.bottom + delta > line->fBottom) + delta = line->fBottom - bounds.bottom; + + ScrollBy (0.0, delta); + fOff_view_time = system_time(); + } + } + + point.x = Bounds().right; + point.y = Bounds().bottom; + ExtendTrackingSelect (point); + } + else + ExtendTrackingSelect (point); +} + +void +RunView::MessageReceived (BMessage *msg) +{ + switch (msg->what) + { + + case M_THEME_FOREGROUND_CHANGE: + case M_THEME_BACKGROUND_CHANGE: + if (!IsHidden()) + Invalidate (Bounds()); + break; + + case M_THEME_FONT_CHANGE: + { + Theme *save (fTheme); + + fTheme = NULL; + SetTheme (save); + break; + } + + case B_SELECT_ALL: + SelectAll(); + break; + + case B_COPY: + if (fSp_start != fSp_end + && be_clipboard->Lock()) + { + BString fText; + GetSelectionText (fText); + + be_clipboard->Clear(); + + BMessage *msg (be_clipboard->Data()); + msg->AddData ("text/plain", B_MIME_TYPE, fText.String(), fText.Length()); + + be_clipboard->Commit(); + be_clipboard->Unlock(); + } + break; + + case M_OFFVIEW_SELECTION: + { + BPoint point; + float delta; + bool bottom; + + msg->FindPoint ("point", &point); + msg->FindBool ("bottom", &bottom); + msg->FindFloat ("delta", &delta); + + if (bottom) + point.y = Bounds().bottom + delta; + else + point.y = Bounds().top - delta; + + ShiftTrackingSelect (point, true, OFFVIEW_TIMER); + break; + } + + case M_LOOKUP_WEBSTER: + { + BString lookup; + msg->FindString ("string", &lookup); + lookup = StringToURI (lookup.String()); + lookup.Prepend ("http://www.m-w.com/cgi-bin/dictionary?va="); + LoadURL (lookup.String()); + } + break; + + case M_LOOKUP_GOOGLE: + { + BString lookup; + msg->FindString ("string", &lookup); + lookup = StringToURI (lookup.String()); + lookup.Prepend ("http://www.google.com/search?q="); + LoadURL (lookup.String()); + } + break; + + case M_LOOKUP_ACRONYM: + { + BString lookup; + msg->FindString ("string", &lookup); + lookup = StringToURI (lookup.String()); + lookup.Prepend ("http://www.acronymfinder.com/af-query.asp?String=exact&Acronym="); + lookup.Append ("&Find=Find"); + LoadURL (lookup.String()); + } + break; + + case M_CLEAR: + { + Clear(); + } + break; + + default: + BView::MessageReceived (msg); + } +} + +void +RunView::ResizeRecalc (void) +{ + float width (Bounds().Width() - (fTheme->TextMargin()*2)); + int16 fSoftie_size (0), fSoftie_used (0); + SoftBreak *fSofties (NULL); + BRect bounds (Bounds()); + BRegion region; + float top (0.0); + + fTheme->ReadLock(); + for (int16 i = 0; i < fLine_count; ++i) + { + float old_top (fLines[i]->fTop), old_bottom (fLines[i]->fBottom); + if (fSoftie_size < fLines[i]->fSoftie_used) + { + delete [] fSofties; + fSofties = new SoftBreak [fSoftie_size = fLines[i]->fSoftie_size]; + } + + fSoftie_used = fLines[i]->fSoftie_used; + memcpy (fSofties, fLines[i]->fSofties, (fSoftie_used * sizeof (SoftBreak))); + + fLines[i]->fTop = top; + fLines[i]->SoftBreaks (fTheme, width); + top = fLines[i]->fBottom + 1.0; + + BRect r (0.0, fLines[i]->fTop, bounds.right, fLines[i]->fBottom); + + if (bounds.Intersects (r) + && (old_top != fLines[i]->fTop + || old_bottom != fLines[i]->fBottom + || fSoftie_used != fLines[i]->fSoftie_used + || memcmp (fSofties, fLines[i]->fSofties, fSoftie_used * sizeof (SoftBreak)))) + region.Include (r); + } + + fTheme->ReadUnlock(); + + if (Window()) + { + if (RecalcScrollBar (true)) + Invalidate (Bounds()); + else + { + int32 count (region.CountRects()), j; + + for (j = 0; j < count; ++j) + Invalidate (region.RectAt (j)); + + if (top <= bounds.bottom) + { + BRect r (bounds); + + r.top = top; + Invalidate (r); + } + } + + Window()->Sync(); + } + + if (fWorking) fWorking->fTop = top; + delete [] fSofties; +} + +void +RunView::FontChangeRecalc (void) +{ + float width (Bounds().Width() - (fTheme->TextMargin()*2)); + float top (0.0); + + for (int16 i = 0; i < fLine_count; ++i) + { + fLines[i]->fTop = top; + + fLines[i]->FigureSpaces(); + fLines[i]->FigureEdges (fTheme, width); + + top = fLines[i]->fBottom + 1.0; + } + + if (fWorking) + fWorking->fTop = top; + + RecalcScrollBar (false); + if (!IsHidden()) + Invalidate (Bounds()); + if (Window()) Window()->UpdateIfNeeded(); +} + +bool +RunView::RecalcScrollBar (bool constrain) +{ + BScrollBar *bar; + + if (fScroller == NULL + || (bar = fScroller->ScrollBar (B_VERTICAL)) == NULL) + return false; + + float value (bar->Value()); + BRect bounds (Bounds()); + bool changed (false); + float bottom (0.0); + float scrollMin, scrollMax; + + bar->GetRange (&scrollMin, &scrollMax); + + if (fLine_count + && (bounds.Contains (BPoint (0.0, 0.0)) == false + || bounds.Contains (BPoint (0.0, fLines[fLine_count - 1]->fBottom)) == false)) + { + bottom = fLines[fLine_count - 1]->fBottom + 5.0; + bar->SetProportion (bounds.Height() / bottom); + bar->SetSteps (10.0, bounds.Height()); + + bottom -= bounds.Height(); + } + + // We don't want the bar to cause a draw/copybits, so we restrict the + // clipping region to nothing + + if (constrain) + { + BRegion region; + ConstrainClippingRegion (®ion); + } + + if (scrollMax != bottom) + { + bar->SetRange (0.0, bottom); + + if (value == scrollMax || scrollMin == scrollMax) + { + bar->SetValue (bottom); + changed = true; + } + } + + if (constrain) + ConstrainClippingRegion (NULL); + + return changed; +} + +void +RunView::Append ( + const char *buffer, + int16 fore, + int16 back, + int16 font) +{ + Append (buffer, strlen (buffer), fore, back, font); +} + +void +RunView::Append ( + const char *buffer, + int32 len, + int16 fore, + int16 back, + int16 font) +{ + if (buffer == NULL) + return; + float width (Bounds().Width() - 10); + int32 place (0); + + assert (fore != Theme::TimestampFore); + assert (back != Theme::TimestampBack); + assert (font != Theme::TimestampFont); + assert (fore != Theme::TimespaceFore); + assert (back != Theme::TimespaceBack); + assert (font != Theme::TimespaceFont); + assert (back != Theme::SelectionBack); + + fTheme->ReadLock(); + + while (place < len) + { + int32 end (place); + + while (end < len && buffer[end] != '\n') + ++end; + + if (end < len) ++end; + + if (fWorking) + { + + URLCrunch crunch (buffer + place, end - place); + BString temp; + int32 url_offset (0), + last_offset (0); + + + while ((url_offset = crunch.Crunch (&temp)) != B_ERROR) + { + fWorking->Append (buffer + place, + (url_offset - last_offset), + width, + fTheme, + fore, + back, + font); + + fWorking->Append (temp.String(), + temp.Length(), + width, + fTheme, + C_URL, + back, + F_URL); + + place += (url_offset - last_offset) + temp.Length(); + last_offset = url_offset + temp.Length(); + } + + if (place < end) + fWorking->Append ( + buffer + place, + end - place, + width, + fTheme, + fore, + back, + font); + } + else + { + float top (0.0); + + if (fLine_count > 0) + top = fLines[fLine_count - 1]->fBottom + 1.0; + +//HERE + fWorking = new Line ( + buffer + place, + 0, + top, + width, + fTheme, + fStamp_format, + fore, + back, + font); + + URLCrunch crunch (buffer + place, end - place); + BString temp; + int32 url_offset (0), + last_offset (0); + + while ((url_offset = crunch.Crunch (&temp)) != B_ERROR) + { + fWorking->Append (buffer + place, + (url_offset - last_offset), + width, + fTheme, + fore, + back, + font); + fWorking->Append (temp.String(), + temp.Length(), + width, + fTheme, + C_URL, + back, + F_URL); + + place += (url_offset - last_offset) + temp.Length(); + last_offset = url_offset + temp.Length(); + } + + if (place < end) + fWorking->Append (buffer + place, + end - place, + width, + fTheme, + fore, + back, + font); + } + + if (fWorking->fLength + && fWorking->fText[fWorking->fLength - 1] == '\n') + { + bool chopped; + + if (Window()) Window()->DisableUpdates(); + + if ((chopped = (fLine_count == LINE_COUNT))) + { + Line *first (fLines[0]); + float shift (first->fBottom + 1); + + for (int16 i = 1; i < LINE_COUNT; ++i) + { + fLines[i]->fTop -= shift; + fLines[i]->fBottom -= shift; + + fLines[i - 1] = fLines[i]; + } + + fWorking->fTop -= shift; + fWorking->fBottom -= shift; + + delete first; + + if (fSp_start.fLine > 0) + fSp_start.fLine--; + else + fSp_start.fOffset = 0; + + if (fSp_end.fLine > 0) + fSp_end.fLine--; + else + fSp_end.fOffset = 0; + + // Recalc the scrollbar so that we have clean drawing + // after the line has been removed + --fLine_count; + RecalcScrollBar (true); + } + + fLines[fLine_count++] = fWorking; + RecalcScrollBar (true); + + Invalidate (Bounds()); + + if (Window()) + { + Window()->EnableUpdates(); + Window()->UpdateIfNeeded(); + } + + fWorking = NULL; + } + + place = end; + } + + fTheme->ReadUnlock(); +} + +void +RunView::Clear (void) +{ + for (int16 i = 0; i < fLine_count; ++i) + delete fLines[i]; + + fLine_count = 0; + RecalcScrollBar (true); + Invalidate(); + + fSp_start.fLine = 0; + fSp_start.fOffset = 0; + fSp_end = fSp_start; + + if (fWorking) + fWorking->fTop = 0.0; +} + +int16 +RunView::LineCount (void) const +{ + return fLine_count; +} + +const char * +RunView::LineAt (int16 which) const +{ + if (which < 0 || which >= fLine_count) + return NULL; + + return fLines[which]->fText; +} + +void +RunView::SetTimeStampFormat (const char *format) +{ + if ((format == NULL + && fStamp_format == NULL) + || (format != NULL + && fStamp_format != NULL + && strcmp (format, fStamp_format) == 0)) + return; + + bool was_on (false); + + if (fStamp_format) + { + delete [] fStamp_format; + fStamp_format = NULL; + was_on = true; + } + + if (format) + fStamp_format = strcpy (new char [strlen (format) + 1], format); + + float width (Bounds().Width() - (fTheme->TextMargin()*2)); + float top (0.0); + + fTheme->ReadLock(); + for (int16 i = 0; i < fLine_count; ++i) + { + fLines[i]->fTop = top; + + fLines[i]->SetStamp (fStamp_format, was_on); + fLines[i]->FigureSpaces(); + fLines[i]->FigureEdges(fTheme, width); + + top = fLines[i]->fBottom + 1.0; + } + fTheme->ReadUnlock(); + + if (fWorking) + { + fWorking->fTop = top; + fWorking->SetStamp (fStamp_format, was_on); + } + + RecalcScrollBar (false); + Invalidate (Bounds()); + if (Window()) Window()->UpdateIfNeeded(); +} + +void +RunView::SetTheme (Theme *t) +{ + if (t == NULL || fTheme == t) + return; + + fTheme = t; + + if (IsHidden()) + { + fFontsdirty = true; + return; + } + FontChangeRecalc(); +} + +SelectPos +RunView::PositionAt (BPoint point) const +{ + int16 i, lfIndex (0); + SelectPos pos (-1, 0); + + if (fLine_count == 0) + return pos; + + // find the line + for (i = 0; i < fLine_count; ++i) + { + if (fLines[i]->fTop > point.y) + break; + lfIndex = i; + } + + // check to make sure we actually did find a line and not just run into fLine_count + if (fLines[lfIndex]->fBottom < point.y) + { + pos.fLine = fLine_count - 1; + pos.fOffset = fLines[fLine_count - 1]->fLength; + return pos; + } + + float height (fLines[lfIndex]->fTop); + int16 sfIndex (0); + + for (i = 0; i < fLines[lfIndex]->fSoftie_used; ++i) + { + if (height > point.y) + break; + + sfIndex = i; + height += fLines[lfIndex]->fSofties[i].fHeight; + } + + float margin (fTheme->TextMargin()); + float width (0); + int16 start (0); + + if (sfIndex) + { + int16 offset (fLines[lfIndex]->fSofties[sfIndex - 1].fOffset); + + width = fLines[lfIndex]->fEdges[offset]; + start = offset + UTF8_CHAR_LEN (fLines[lfIndex]->fText[offset]); + } + + for (i = start; i <= fLines[lfIndex]->fSofties[sfIndex].fOffset; ++i) + if (fLines[lfIndex]->fEdges[i] + margin - width >= point.x) + break; + + pos.fLine = lfIndex; + pos.fOffset = min_c (i, fLines[lfIndex]->fSofties[sfIndex].fOffset); + if (pos.fOffset > 0) pos.fOffset += UTF8_CHAR_LEN (fLines[pos.fLine]->fText[pos.fOffset]); + + return pos; +} + +BPoint +RunView::PointAt (SelectPos s) const +{ + return BPoint(fLines[s.fLine]->fTop + fLines[s.fLine]->fBottom / 2.0, fLines[s.fLine]->fEdges[s.fOffset]); +} + +void +RunView::GetSelectionText (BString &string) const +{ + if (fSp_start == fSp_end) + return; + + if (fSp_start.fLine == fSp_end.fLine) + { + const char *line (LineAt (fSp_start.fLine)); + string.Append (line + fSp_start.fOffset, fSp_end.fOffset - fSp_start.fOffset); + return; + } + + for (int32 i = fSp_start.fLine; i <= fSp_end.fLine; i++) + { + const char *line (LineAt (i)); + if (i == fSp_start.fLine) + { + line += fSp_start.fOffset; + string.Append (line); + } + else if (i == fSp_end.fLine) + { + string.Append (line, fSp_end.fOffset); + break; + } + else + string.Append (line); + } +} + +bool +RunView::IntersectSelection (const SelectPos &start, const SelectPos &end) const +{ + if (fSp_start.fLine == fSp_end.fLine) + { + if (start.fLine == fSp_start.fLine && start.fOffset >= fSp_start.fOffset && start.fOffset < fSp_end.fOffset) + return true; + if (end.fLine == fSp_start.fLine && end.fOffset >= fSp_start.fOffset && end.fOffset < fSp_end.fOffset) + return true; + } + else + { + if (start.fLine > fSp_start.fLine && start.fLine < fSp_end.fLine) + return true; + if (end.fLine > fSp_start.fLine && end.fLine < fSp_end.fLine) + return true; + if (start.fLine == fSp_start.fLine && start.fOffset >= fSp_start.fOffset) + return true; + if (end.fLine == fSp_start.fLine && end.fOffset >= fSp_start.fOffset) + return true; + if (start.fLine == fSp_end.fLine && start.fOffset < fSp_end.fOffset) + return true; + if (end.fLine == fSp_end.fLine && end.fOffset < fSp_end.fOffset) + return true; + } + + return false; +} + +BRect +RunView::GetTextFrame(const SelectPos &start, const SelectPos &end) const +{ + return BRect (0.0, fLines[(start.fLine > 0) ? (start.fLine - 1) : 0]->fTop, + Bounds().Width(), fLines[end.fLine]->fBottom); +} + +void +RunView::Select (const SelectPos &start, const SelectPos &end) +{ + if (fSp_start != fSp_end) + { + if (start == end || !IntersectSelection (start, end)) + { + BRect frame (GetTextFrame (fSp_start, fSp_end)); + + fSp_start = start; + fSp_end = start; + Invalidate (frame); + } + else + { + if (fSp_start.fLine < start.fLine || (fSp_start.fLine == start.fLine && fSp_start.fOffset < start.fOffset)) + { + BRect frame (GetTextFrame (fSp_start, start)); + + fSp_start = start; + Invalidate (frame); + } + + if (end.fLine < fSp_end.fLine || (fSp_end.fLine == end.fLine && end.fOffset < fSp_end.fOffset)) + { + BRect frame (GetTextFrame (end, fSp_end)); + + fSp_end = end; + Invalidate (frame); + } + } + } + + if (fSp_start == fSp_end) + { + fSp_start = start; + fSp_end = end; + + if (fSp_start != fSp_end) + { + BRect frame (GetTextFrame (start, end)); + + Invalidate (frame); + } + } + else // extension + { + if (start.fLine < fSp_start.fLine || (start.fLine == fSp_start.fLine && start.fOffset < fSp_start.fOffset)) + { + BRect frame (GetTextFrame (start, fSp_start)); + + fSp_start = start; + Invalidate (frame); + } + + if (end.fLine > fSp_end.fLine || (end.fLine == fSp_end.fLine && end.fOffset > fSp_end.fOffset)) + { + BRect frame (GetTextFrame (fSp_end, end)); + + fSp_end = end; + Invalidate (frame); + } + } +} + +void +RunView::SelectAll (void) +{ + if (fLine_count) + { + fSp_start = SelectPos (0, 0); + fSp_end = SelectPos (fLine_count-1, fLines[fLine_count-1]->fLength); + Invalidate(Bounds()); + } +} + +void +RunView::SetClippingName (const char *name) +{ + delete [] fClipping_name; + fClipping_name = new char[strlen(name) + 1]; + memcpy (fClipping_name, name, strlen(name)); + fClipping_name[strlen(name)] = '\0'; +} + +Line::Line ( + const char *buffer, + int16 len, + float top, + float width, + Theme *theme, + const char *stamp_format, + int16 fore, + int16 back, + int16 font) + : fText (NULL), + fStamp (time(NULL)), + fUrls (NULL), + fSpaces (NULL), + fEdges (NULL), + fFcs (NULL), + fSofties (NULL), + fTop (top), + fBottom (0.0), + fLength (len), + fSpace_count (0), + fEdge_count (0), + fFc_count (0), + fSoftie_size (0), + fSoftie_used (0) +{ + // Very important to call SetStamp before Append, It would look real funny otherwise! + SetStamp( stamp_format, false ); + + Append( buffer, len, width, theme, fore, back, font ); +} + +Line::~Line (void) +{ + delete [] fSpaces; + delete [] fEdges; + delete [] fFcs; + delete [] fText; + delete [] fSofties; + + if (fUrls) + { + while (fUrls->CountItems() > 0) + delete fUrls->RemoveItemAt(0L); + delete fUrls; + } +} + +void +Line::Append ( + const char *buffer, + int16 len, + float width, + Theme *theme, + int16 fore, + int16 back, + int16 font) +{ + int16 save (fLength); + char *new_fText; + + new_fText = new char [fLength + len + 1]; + + if (fText != NULL) + { + memcpy (new_fText, fText, fLength); + delete [] fText; + } + + memcpy (new_fText + fLength, buffer, len); + fLength += len; + new_fText[fLength] = '\0'; + + // replace Tab chars with spaces. + // todo: This should be temp until RunView can properly + // display tabs. + for( char* pos = new_fText + save; *pos; ++pos ) + { + if( '\t' == *pos ) + { + *pos = ' '; + } + } + + fText = new_fText; + + FigureFontColors (save, fore, back, font); + + if (fore == C_URL) + { + if (!fUrls) + fUrls = new urllist; + fUrls->AddItem (new URL (buffer, save, len)); + } + + if (fText[fLength - 1] == '\n') + { + FigureSpaces(); + FigureEdges (theme, width); + } +} + +void +Line::FigureSpaces (void) +{ + const char spacers[] = " \t\n-\\/"; + const char *buffer (fText); + size_t offset (0), n; + int16 count (0); + + delete [] fSpaces; + fSpace_count = 0; + while ((n = strcspn (buffer + offset, spacers)) < fLength - offset) + { + ++count; + offset += n + 1; + } + + fSpaces = new int16 [count]; + + offset = 0; + while ((n = strcspn (buffer + offset, spacers)) < fLength - offset) + { + fSpaces[fSpace_count++] = n + offset; + offset += n + 1; + } +} + +void +Line::FigureFontColors ( + int16 pos, + int16 fore, + int16 back, + int16 font) +{ + if (fFc_count) + { + int16 last_fore = -1; + int16 last_back = -1; + int16 last_font = -1; + int16 i; + + // we have fFcs, so we backtrack for last of each fWhich + for (i = fFc_count - 1; i >= 0; --i) + { + if (last_fore < 0 + && fFcs[i].fWhich == FORE_WHICH) + last_fore = i; + else if (last_back < 0 + && fFcs[i].fWhich == BACK_WHICH) + last_back = i; + else if (last_font < 0 + && fFcs[i].fWhich == FONT_WHICH) + last_font = i; + + if (last_fore >= 0 + && last_back >= 0 + && last_font >= 0) + break; + } + + // now figure out how many more we need + int16 count = 0; + if (fFcs[last_fore].fIndex != fore) + ++count; + if (fFcs[last_back].fIndex != back) + ++count; + if (fFcs[last_font].fIndex != font) + ++count; + + if (count) + { + FontColor *new_fFcs; + new_fFcs = new FontColor [fFc_count + count]; + memcpy (new_fFcs, fFcs, fFc_count * sizeof (FontColor)); + delete [] fFcs; + fFcs = new_fFcs; + + if (fFcs[last_fore].fIndex != fore) + { + fFcs[fFc_count].fWhich = FORE_WHICH; + fFcs[fFc_count].fOffset = pos; + fFcs[fFc_count].fIndex = fore; + ++fFc_count; + } + + if (fFcs[last_back].fIndex != back) + { + fFcs[fFc_count].fWhich = BACK_WHICH; + fFcs[fFc_count].fOffset = pos; + fFcs[fFc_count].fIndex = back; + ++fFc_count; + } + + if (fFcs[last_font].fIndex != font) + { + fFcs[fFc_count].fWhich = FONT_WHICH; + fFcs[fFc_count].fOffset = pos; + fFcs[fFc_count].fIndex = font; + ++fFc_count; + } + } + } + else + { + fFcs = new FontColor [fFc_count = 3]; + fFcs[0].fWhich = FORE_WHICH; + fFcs[0].fOffset = 0; + fFcs[0].fIndex = fore; + fFcs[1].fWhich = BACK_WHICH; + fFcs[1].fOffset = 0; + fFcs[1].fIndex = back; + fFcs[2].fWhich = FONT_WHICH; + fFcs[2].fOffset = 0; + fFcs[2].fIndex = font; + } +} + +void +Line::FigureEdges ( + Theme *theme, + float width) +{ + delete [] fEdges; + fEdges = new int16 [fLength]; + + int16 cur_fFcs (0), next_fFcs (0), cur_font (0); + + fEdge_count = 0; + while (cur_fFcs < fFc_count) + { + if (fFcs[cur_fFcs].fWhich == FONT_WHICH) + { + cur_font = cur_fFcs; + break; + } + + ++cur_fFcs; + } + + while (cur_fFcs < fFc_count) + { + int16 last_offset (fFcs[cur_fFcs].fOffset); + next_fFcs = cur_fFcs + 1; + + while (next_fFcs < fFc_count) + { + // We want to break at every difference + // but, we want to break on a font if available + if (fFcs[next_fFcs].fOffset > last_offset) + { + while (next_fFcs < fFc_count + && fFcs[next_fFcs].fWhich != FONT_WHICH + && next_fFcs + 1 < fFc_count + && fFcs[next_fFcs + 1].fOffset == fFcs[next_fFcs].fOffset) + ++next_fFcs; + + break; + } + ++next_fFcs; + } + + if (fFcs[cur_fFcs].fWhich == FONT_WHICH) + cur_font = cur_fFcs; + + int16 ccount; + int16 seglen; + + if (next_fFcs == fFc_count) + { + ccount = CountChars (fFcs[cur_fFcs].fOffset, fLength - fFcs[cur_fFcs].fOffset); + seglen = fLength - fFcs[cur_fFcs].fOffset; + } + else + { + ccount = CountChars ( + fFcs[cur_fFcs].fOffset, + fFcs[next_fFcs].fOffset - fFcs[cur_fFcs].fOffset); + seglen = fFcs[next_fFcs].fOffset - fFcs[cur_fFcs].fOffset; + } + + // const BFont &f (theme->FontAt (fFcs[cur_font].fIndex)); + TextRender *tr=theme->TextRenderAt (fFcs[cur_font].fIndex); + +#ifdef __INTEL__ + float eshift[ccount]; +#else + float *eshift = new float[ccount]; +#endif + + /* f.GetEscapements ( + fText + fFcs[cur_fFcs].fOffset, + ccount, + eshift);*/ + +// if(tr) + tr->GetEscapements ( + fText + fFcs[cur_fFcs].fOffset, + ccount, + eshift); + + // This is not perfect, because we are including the left edge, + // but BFont::GetEdges doesn't seem to work as we'd like + + int16 i; + float size=0; + +// if(tr) + size=tr->Size(); + + + float incrementor = (fEdge_count > 0) ? fEdges[fEdge_count - 1] : 0; + + for (i = 0; i < ccount; ++i) + { + incrementor += eshift[i] * size; + + fEdges[fEdge_count+i] = (int16) incrementor; + + // this little backfTracking routine is necessary in the case where an fFcs change + // comes immediately after a UTF8-char, since all but the first edge will be 0 + // and thus the new edge's starting position will be thrown off if we don't + // backtrack to the beginning of the char + if ((fEdge_count + i > 0) && fEdges[fEdge_count + i - 1] == 0) + { + int32 temp = fEdge_count + i - 1; + while (fEdges[--temp] == 0); + fEdges[fEdge_count + i] += fEdges[temp]; + } + } + + for (i = fFcs[cur_fFcs].fOffset; i < fFcs[cur_fFcs].fOffset + seglen;) + { + int32 len (UTF8_CHAR_LEN (fText[i]) - 1); + + if (len) + { + int16 k; + for (k = fEdge_count + ccount - 1; k > i; --k) + fEdges[k + len] = fEdges[k]; + + for (k = 1; k <= len; ++k) + fEdges[i + k] = 0; + + ccount += len; + } + + i += len + 1; + } + + cur_fFcs = next_fFcs; + fEdge_count += ccount; +#ifndef __INTEL__ + delete [] eshift; +#endif + } + + SoftBreaks (theme, width); +} + + +void +Line::AddSoftBreak (SoftBreakEnd sbe, float &start, uint16 &fText_place, + int16 &font, float &width, float &start_width, Theme *theme) +{ + fText_place = sbe.fOffset; + + if (fSoftie_size < fSoftie_used + 1) + { + SoftBreak *new_softies; + + new_softies = new SoftBreak [fSoftie_size += SOFTBREAK_STEP]; + + if (fSofties) + { + memcpy (new_softies, fSofties, sizeof (SoftBreak) * fSoftie_used); + delete [] fSofties; + } + + fSofties = new_softies; + } + + // consume whitespace + while (fText_place + 1 < fLength + && isspace (fText[fText_place + 1])) + ++fText_place; + + fSofties[fSoftie_used].fOffset = fText_place; + fSofties[fSoftie_used].fHeight = 0.0; + fSofties[fSoftie_used].fAscent = 0.0; + + int16 last (font); + while (font < fFc_count) + { + TextRender *tr = theme->TextRenderAt (fFcs[font].fIndex); + + font_height fh; + float height; + + tr->GetHeight (&fh); + + height = ceil (fh.ascent + fh.descent + fh.leading); + if (fSofties[fSoftie_used].fHeight < height) + fSofties[fSoftie_used].fHeight = height; + if (fSofties[fSoftie_used].fAscent < fh.ascent) + fSofties[fSoftie_used].fAscent = fh.ascent; + + // now try and find next + while (++font < fFc_count) + if (fFcs[font].fWhich == FONT_WHICH) + break; + + if (font == fFc_count + || fFcs[font].fOffset > fText_place) + { + font = last; + break; + } + + last = font; + } + + if (fText_place < fLength) + start = fEdges[fText_place]; + + fBottom += fSofties[fSoftie_used++].fHeight; + fText_place += UTF8_CHAR_LEN (fText[fText_place]); + width = start_width - (theme->SoftLineIndent()); +} + +void +Line::SoftBreaks (Theme *theme, float start_width) +{ + float margin (theme->TextMargin()); + float width (start_width); + float start (0.0); + uint16 fText_place (0); + int16 space_place (0); + int16 font (0); + + fSoftie_used = 0; + fBottom = fTop; + + // find first font + while (font < fFc_count && fFcs[font].fWhich != FONT_WHICH) + ++font; + + while (fText_place < fLength) + { + while (space_place < fSpace_count) + { + if (fEdges[fSpaces[space_place]] - start > width) + break; + + ++space_place; + } + + // we've reached the end of the line (but it might not all fit) + // or we only have one space, so we check if we need to split the word + if (space_place == fSpace_count + || space_place == 0 + || fSpaces[space_place - 1] < fText_place) + { + // everything fits.. how wonderful (but we want at least one softbreak) + if (fEdge_count == 0) + { + AddSoftBreak (SoftBreakEnd(fLength - 1), start, fText_place, font, width, start_width, theme); + break; + } + + int16 i (fEdge_count - 1); + + while (fEdges[i] == 0) + --i; + + if (fEdges[i] - start <= width) + { + AddSoftBreak (SoftBreakEnd(fLength - 1), start, fText_place, font, width, start_width, theme); + continue; + } + + // we force at least one character + // your font may be a little too large for your window! + fText_place += UTF8_CHAR_LEN (fText[fText_place]); + while (fText_place < fLength) + { + if (fEdges[fText_place] - start > width - margin) + break; + + fText_place += UTF8_CHAR_LEN (fText[fText_place]); + } + AddSoftBreak (SoftBreakEnd(fText_place), start, fText_place, font, width, start_width, theme); + continue; + } + + // we encountered more than one space, so we rule out having to + // split the word, if the current word will fit within the bounds + int16 ccount1, ccount2; + --space_place; + + ccount1 = fSpaces[space_place]; + ccount2 = fSpaces[space_place+1] - ccount1; + + int16 i (ccount1 - 1); + while (fEdges[i] == 0) + --i; + + if (fEdges[ccount1 + ccount2] - fEdges[i] < width - margin) + { + AddSoftBreak (SoftBreakEnd(fSpaces[space_place]), start, fText_place, font, width, start_width, theme); + continue; + } + + // We need to break up the really long word + fText_place = fSpaces[space_place]; + while (fText_place < fEdge_count) + { + if ((fEdges[fText_place] - start) > width) + break; + + fText_place += UTF8_CHAR_LEN (fText[fText_place]); + } + } + + fBottom -= 1.0; +} + +int16 +Line::CountChars (int16 pos, int16 len) +{ + int16 ccount (0); + + if (pos >= fLength) + return ccount; + + if (pos + len > fLength) + len = fLength - pos; + + register int16 i = pos; + while (i < pos + len) + { + i += UTF8_CHAR_LEN(fText[i]); + ++ccount; + } + + return ccount; +} + +size_t +Line::SetStamp (const char *format, bool was_on) +{ + size_t size (0); + int32 i (0); + + if (was_on) + { + int16 offset (fFcs[4].fOffset + 1); + + if (fUrls) + { + for (i = 0; i < fUrls->CountItems(); i++) + fUrls->ItemAt(i)->fOffset -= offset; + } + memmove (fText, fText + offset, fLength - offset); + fText[fLength -= offset] = '\0'; + + for (i = 6; i < fFc_count; ++i) + { + fFcs[i].fOffset -= offset; + fFcs[i - 6] = fFcs[i]; + } + + fFc_count -= 6; + } + + if (format) + { + char buffer[1024]; + struct tm curTime; + + localtime_r (&fStamp, &curTime); + size = strftime (buffer, 1023, format, &curTime); + if (fUrls) + { + for (i = 0; i < fUrls->CountItems(); i++) + fUrls->ItemAt(i)->fOffset += size; + } + + char *new_fText; + + new_fText = new char [fLength + size + 2]; + memcpy (new_fText, buffer, size); + new_fText[size++] = ' '; + new_fText[size] = '\0'; + + if (fText) + { + memcpy (new_fText + size, fText, fLength); + delete [] fText; + } + + fText = new_fText; + fText[fLength += size] = '\0'; + + FontColor *new_fFcs; + new_fFcs = new FontColor [fFc_count + 6]; + + if (fFcs) + { + memcpy ( + new_fFcs + 6, + fFcs, + fFc_count * sizeof (FontColor)); + delete [] fFcs; + } + fFcs = new_fFcs; + fFc_count += 6; + + fFcs[0].fWhich = FORE_WHICH; + fFcs[0].fIndex = Theme::TimestampFore; + fFcs[0].fOffset = 0; + fFcs[1].fWhich = BACK_WHICH; + fFcs[1].fIndex = Theme::TimestampBack; + fFcs[1].fOffset = 0; + fFcs[2].fWhich = FONT_WHICH; + fFcs[2].fIndex = Theme::TimestampFont; + fFcs[2].fOffset = 0; + + fFcs[3].fWhich = FORE_WHICH; + fFcs[3].fIndex = Theme::TimespaceFore; + fFcs[3].fOffset = size - 1; + fFcs[4].fWhich = BACK_WHICH; + fFcs[4].fIndex = Theme::TimespaceBack; + fFcs[4].fOffset = size - 1; + fFcs[5].fWhich = FONT_WHICH; + fFcs[5].fIndex = Theme::TimespaceFont; + fFcs[5].fOffset = size - 1; + + for (i = 6; i < fFc_count; ++i) + fFcs[i].fOffset += size; + } + + return size; +} + +void +Line::SelectWord (int16 *start, int16 *end) +{ + int16 start_tmp (*start), end_tmp (*end); + + while(start_tmp > 0 && fText[start_tmp-1] != ' ') + start_tmp--; + + while ((end_tmp - 1) < fLength && fText[end_tmp] != ' ') + end_tmp++; + + while (end_tmp >= fLength) + --end_tmp; + + *start = start_tmp; + *end = end_tmp; +} + +bool +RunView::FindText(const char *text) +{ + bool result (false); + if (text != NULL) + { + for (int32 i = 0; i < fLine_count; i++) + { + char *offset (NULL); + if ((offset = strstr((const char *)fLines[i], text)) != NULL) + { + SelectPos start (i, offset - text), + end (i, (offset - text) + strlen(text)); + Select(start, end); + ScrollTo(0.0, fLines[i]->fTop); + result = true; + break; + } + } + } + return result; +} + +void RunView::LoadURL(const char *url) { + BString argument (url); + if (argument.FindFirst ("://") == B_ERROR) + { + + if (argument.IFindFirst ("www") == 0) + argument.Prepend ("http://"); + + else if (argument.IFindFirst ("ftp") == 0) + argument.Prepend ("ftp://"); + } + + const char *args[] = { argument.String(), 0 }; + + if (argument.IFindFirst ("file:") == 0) + { + // The URL is guaranteed to be at least "file:/" + BString file(argument.String() + 5); + + // todo: Should probably see if the file exists before going through + // all this, but, oh well... ;) + file.Prepend("/boot/beos/system/Tracker "); + file += " &"; // just in case + + system(file.String()); + } + else if (argument.IFindFirst ("mailto:") == 0) + { + be_roster->Launch ("text/x-email", 1, const_cast(args)); + } + else + { + be_roster->Launch ("text/html", 1, const_cast(args)); + } +} + +void RunView::ScrollToBottom(void) { + if (fLine_count != 0) { + BScrollBar *scroll = fScroller->ScrollBar(B_VERTICAL); + if (scroll != NULL) scroll->SetValue(fLines[fLine_count - 1]->fBottom); + ScrollTo(0.0, fLines[fLine_count - 1]->fBottom); + }; +}; + +void RunView::ScrollToSelection(void) { + if (fLine_count == 0) return; + + if (fSp_start != fSp_end) + ScrollTo(0.0, fLines[fSp_start.fLine]->fTop); + +}; diff --git a/libs/librunview/RunView.h b/libs/librunview/RunView.h new file mode 100644 index 0000000..01aa3d8 --- /dev/null +++ b/libs/librunview/RunView.h @@ -0,0 +1,190 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Rene Gollent + * Todd Lair + */ + +#ifndef RUNVIEW_H_ +#define RUNVIEW_H_ + +#define LINE_COUNT 1000 + +#include + +const uint32 M_LOOKUP_WEBSTER = 'rvlw'; +const uint32 M_LOOKUP_GOOGLE = 'rvlg'; +const uint32 M_LOOKUP_ACRONYM = 'rvla'; +const uint32 M_CLEAR = 'rvcl'; + +const uint32 M_OFFVIEW_SELECTION = 'rvos'; +const uint32 M_THEME_FOREGROUND_CHANGE = 'rvtf'; +const uint32 M_THEME_BACKGROUND_CHANGE = 'rvtb'; +const uint32 M_THEME_FONT_CHANGE = 'rvto'; + +#define C_URL 0 +#define F_URL 0 + +struct Line; +class Theme; +class RunView; +class BScrollView; +class BCursor; +class BMessageRunner; +class BPopUpMenu; + +class SelectPos +{ + public: + + int16 fLine; + int16 fOffset; + + SelectPos ( + int16 selLine = 0, + int16 selOffset = 0) + : fLine (selLine), + fOffset (selOffset) + { } + + SelectPos (const SelectPos &pos) + : fLine (pos.fLine), + fOffset (pos.fOffset) + { } + + ~SelectPos (void) + { } + + SelectPos &operator = (const SelectPos &pos) + { + fLine = pos.fLine; + fOffset = pos.fOffset; + + return *this; + } + + inline int operator == (const SelectPos &rhs) const + { + return ((fLine == rhs.fLine) && (fOffset == rhs.fOffset)); + } + + inline int operator != (const SelectPos &rhs) const + { + return (!(*this == rhs)); + } + + +}; + +class RunView : public BView +{ + BScrollView *fScroller; + BCursor *fURLCursor; + Theme *fTheme; + + Line *fWorking; + Line *fLines[LINE_COUNT]; + int16 fLine_count, + fClickCount; + + char *fStamp_format; + char *fClipping_name; + + SelectPos fSp_start, fSp_end; + + int32 fTracking; + SelectPos fTrack_offset; + BMessageRunner *fOff_view_runner; + bigtime_t fOff_view_time; + + bool fResizedirty; + bool fFontsdirty; + BPopUpMenu *fMyPopUp; + BPoint fLastClick; + bigtime_t fLastClickTime; + + + bool RecalcScrollBar (bool constrain); + void ResizeRecalc (void); + void FontChangeRecalc (void); + void ExtendTrackingSelect (BPoint); + void ShiftTrackingSelect (BPoint, bool, bigtime_t); + void CheckURLCursor (BPoint); + void BuildPopUp (void); + + bool CheckClickBounds (const SelectPos &, const BPoint &) const; + void LoadURL(const char *url); + + public: + + RunView ( + BRect, + const char *, + Theme *, + uint32 = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 = 0UL); + virtual ~RunView (void); + + virtual void AttachedToWindow (void); + virtual void DetachedFromWindow (void); + virtual void FrameResized (float, float); + virtual void TargetedByScrollView (BScrollView *); + virtual void Show (); + virtual void Draw (BRect); + virtual void MessageReceived (BMessage *); + + virtual void SetViewColor (rgb_color); + void SetViewColor (uchar red, uchar green, uchar blue, uchar alpha = 255) + { rgb_color color = {red, green, blue, alpha}; SetViewColor (color); } + + + virtual void MouseDown (BPoint); + virtual void MouseMoved (BPoint, uint32, const BMessage *); + virtual void MouseUp (BPoint); + + + void Append (const char *, int32, int16, int16, int16); + void Append (const char *, int16, int16, int16); + + void Clear (void); + + int16 LineCount (void) const; + const char *LineAt (int16) const; + + void SetTimeStampFormat (const char *); + void SetTheme (Theme *); + + SelectPos PositionAt (BPoint) const; + BPoint PointAt (SelectPos) const; + + BRect GetTextFrame (const SelectPos &, const SelectPos &) const; + bool IntersectSelection (const SelectPos &, const SelectPos &) const; + void GetSelectionText (BString &) const; + void Select (const SelectPos &, const SelectPos &); + void SelectAll (void); + void SetClippingName (const char *); + bool FindText(const char *); + + void ScrollToBottom(void); + void ScrollToSelection(void); + + + +}; + +#endif diff --git a/libs/librunview/SmileTextRender.h b/libs/librunview/SmileTextRender.h new file mode 100644 index 0000000..3eebd03 --- /dev/null +++ b/libs/librunview/SmileTextRender.h @@ -0,0 +1,53 @@ +#ifndef _SmileTextRender_H_ +#define _SmileTextRender_H_ + +#include "TextRender.h" +#include +#include + +#include +#include +#include +#include + +#include "Emoticor.h" + +class SmileTextRender : public TextRender +{ + public: + + SmileTextRender():TextRender(){}; + + virtual ~SmileTextRender() {}; + + virtual void Render(BView *target,const char* txt,int16 num,BPoint pos) { + + BBitmap *pointer=NULL; + BString f(txt,num); + + if(Emoticor::Get()->Config()->FindPointer(f.String(),(void**)&pointer)==B_OK) + { + target->SetDrawingMode( B_OP_ALPHA ); + target->DrawBitmapAsync( pointer,BPoint(pos.x, pos.y- (Emoticor::Get()->Config()->GetEmoticonSize()/2)) ); + target->SetDrawingMode( B_OP_OVER ); + } + }; + + + virtual float Size(){ return Emoticor::Get()->Config()->GetEmoticonSize();} + + virtual void GetHeight(font_height *h) + { + h->descent = h->ascent = Emoticor::Get()->Config()->GetEmoticonSize()/2; + h->leading=0; + }; + + virtual void + GetEscapements(const char * /*charArray*/, int32 numChars,float escapementArray[]) + { + //font.GetEscapements(charArray,numChars,escapementArray); + escapementArray[0]=1; + for(int i=1;i + +class TextRender +{ + public: + TextRender(){}; + virtual ~TextRender() {}; + + virtual void Render(BView *target,const char*,int16 num,BPoint pos) = 0; + virtual void GetHeight(font_height *height) = 0; + virtual void GetEscapements(const char charArray[], int32 numChars,float escapementArray[])=0; + virtual float Size() = 0; + // + +}; +#endif diff --git a/libs/librunview/Theme.cpp b/libs/librunview/Theme.cpp new file mode 100644 index 0000000..0eab2b7 --- /dev/null +++ b/libs/librunview/Theme.cpp @@ -0,0 +1,265 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Rene Gollent + * Todd Lair + * Andrea Anzani, andrea.anzani@gmail.com + */ + +#define NUMBER_THEME_READERS 1000 + +#include +#include +#include +#include +#include //fix +#include + +#include "Theme.h" +#include "NormalTextRender.h" + +int16 Theme::TimestampFore = 0; +int16 Theme::TimestampBack = 0; +int16 Theme::TimestampFont = 0; +int16 Theme::TimespaceFore = 1; +int16 Theme::TimespaceBack = 1; +int16 Theme::TimespaceFont = 1; +int16 Theme::NormalFore = 2; +int16 Theme::NormalBack = 2; +int16 Theme::NormalFont = 2; +int16 Theme::SelectionBack = 3; + +//at least we use a 'normal' text render + + +Theme::Theme ( + const char *n, + int16 foreCount, + int16 backCount, + int16 renderCount) + : name (NULL), + fores (NULL), + backs (NULL), + text_renders (NULL), + fore_count (max_c (foreCount, 4)), + back_count (max_c (backCount, 4)), + render_count (max_c (renderCount, 4)) +{ + + fSoftLineIndent = (float)(MARGIN_WIDTH / 2.0); + fTextMargin = (float)(MARGIN_WIDTH / 2.0); + + name = strcpy (new char [strlen (n) + 1], n); + + fores = new rgb_color [fore_count]; + backs = new rgb_color [back_count]; + + normal_textrender = new NormalTextRender(be_plain_font); + + text_renders = (TextRender**)malloc(render_count*sizeof(TextRender*)); + for ( int i=0; i= fore_count || which < 0) + return color; + + return fores[which]; +} + +const rgb_color +Theme::BackgroundAt (int16 which) const +{ + rgb_color color = {255, 255, 255, 255}; + + if (which >= back_count || which < 0) + return color; + + return backs[which]; +} +/* +const BFont & +Theme::FontAt (int16 which) const +{ + if (which >= font_count || which < 0) + return *be_plain_font; + + return fonts[which]; +} +*/ + +TextRender* +Theme::TextRenderAt (int16 which) +{ + if ( which < 0 ){ + //printf("Theme::TextRenderAt(): which < 0 (%d)\n", which); + return normal_textrender; + } + if ( which >= render_count ){ + //printf("Theme::TextRenderAt(): which >= render_count (%d, %d)\n", which, render_count); + return normal_textrender; + } + + return text_renders[which]; +} + +bool +Theme::SetForeground (int16 which, const rgb_color color) +{ + if (which >= fore_count || which < 0) + return false; + + fores[which] = color; + return true; +} + +bool +Theme::SetBackground (int16 which, const rgb_color color) +{ + if (which >= back_count || which < 0) + return false; + + backs[which] = color; + return true; +} + + +bool +Theme::SetTextRender(int16 which,TextRender *trender) +{ + + + if (which >= render_count || which < 0 || !trender) + return false; + + text_renders[which] = trender; + return true; +} + +void +Theme::AddView (BView *view) +{ + list.AddItem (view); +} + +void +Theme::RemoveView (BView *view) +{ + list.RemoveItem (view); +} + +void +Theme::SetTextMargin(float margin) +{ + fTextMargin = margin; +} + +void +Theme::SetSoftLineIndent(float indent) +{ + fSoftLineIndent = indent; +} diff --git a/libs/librunview/Theme.h b/libs/librunview/Theme.h new file mode 100644 index 0000000..fb53413 --- /dev/null +++ b/libs/librunview/Theme.h @@ -0,0 +1,120 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Rene Gollent + * Todd Lair + */ + +#ifndef THEME_H_ +#define THEME_H_ + +#include +#include +#include + +#include "TextRender.h" + +class BView; +class NormalTextRender; + +#define MARGIN_WIDTH 10.0 //default value, double of fTextMargin +#define MARGIN_INDENT 10.0 //default value, double of fSoftLineIndent + +class Theme +{ + char *name; + rgb_color *fores; + rgb_color *backs; + TextRender **text_renders; //FIX!! + + int16 fore_count; + int16 back_count; + int16 render_count; + + BList list; + sem_id sid; + + float fSoftLineIndent; + float fTextMargin; + NormalTextRender* normal_textrender; + + public: + + static int16 TimestampFore; + static int16 TimestampBack; + static int16 TimestampFont; + static int16 TimespaceFore; + static int16 TimespaceBack; + static int16 TimespaceFont; + static int16 NormalFore; + static int16 NormalBack; + static int16 NormalFont; + static int16 SelectionBack; + + Theme ( + const char *, + int16, + int16, + int16); + virtual ~Theme (void); + + const char *Name (void) const + { return name; } + + void ReadLock (void); + void ReadUnlock (void); + void WriteLock (void); + void WriteUnlock (void); + + int16 CountForegrounds (void) const; + int16 CountBackgrounds (void) const; +// int16 CountFonts (void) const; + int16 CountTextRenders (void) const; + + const rgb_color ForegroundAt (int16) const; + const rgb_color BackgroundAt (int16) const; + + //const BFont &FontAt (int16) const; + + TextRender* TextRenderAt(int16); + + bool SetForeground (int16, const rgb_color); + bool SetForeground (int16 w, uchar r, uchar g, uchar b, uchar a = 255) + { rgb_color color = {r, g, b, a}; return SetForeground (w, color); } + bool SetBackground (int16, const rgb_color); + bool SetBackground (int16 w, uchar r, uchar g, uchar b, uchar a = 255) + { rgb_color color = {r, g, b, a}; return SetBackground (w, color); } + + //bool SetFont (int16, const BFont &); + bool SetTextRender(int16, TextRender *); + + void SetSoftLineIndent(float indent); + void SetTextMargin(float margin); + + float TextMargin() const { return fTextMargin; } + float SoftLineIndent() const { return fSoftLineIndent; } + + + + void AddView (BView *); + void RemoveView (BView *); + + +}; + +#endif diff --git a/libs/librunview/URLCrunch.cpp b/libs/librunview/URLCrunch.cpp new file mode 100644 index 0000000..c8aaf7e --- /dev/null +++ b/libs/librunview/URLCrunch.cpp @@ -0,0 +1,99 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Rene Gollent + * Todd Lair + */ + +#include + +#include "URLCrunch.h" + +URLCrunch::URLCrunch (const char *data, int32 len) + : buffer (""), + current_pos (0) +{ + buffer.Append (data, len); +} + +URLCrunch::~URLCrunch (void) +{ +} + +int32 +URLCrunch::Crunch (BString *url) +{ + if (current_pos >= buffer.Length()) + return B_ERROR; + + const int32 tagNum = 7; + const char *tags[tagNum] = + { + "http://", + "https://", + "www.", + "ftp://", + "ftp.", + "file:/", + "mailto:" + }; + + int32 marker (buffer.Length()); + int32 pos (current_pos); + int32 url_length (0); + int32 markers[tagNum]; + int32 i(0); + + for (i = 0; i < tagNum; ++i) + markers[i] = buffer.IFindFirst (tags[i], pos); + + for (i = 0; i < tagNum; ++i) + + if (markers[i] != B_ERROR + && markers[i] < marker) + { + url_length = markers[i] + strlen(tags[i]); + + url_length += strcspn (buffer.String() + url_length, " \t\n|\\<>\")(][}{;'*^"); + + + int len (strlen (tags[i])); + + if (url_length - markers[i] > len + && (isdigit (buffer[markers[i] + len]) + || isalpha (buffer[markers[i] + len]))) + { + marker = markers[i]; + pos = url_length + 1; + url_length -= marker; + } + else + pos = markers[i] + 1; + } + + if (marker < buffer.Length()) + { + *url = ""; + + url->Append (buffer.String() + marker, url_length); + } + + current_pos = pos; + + return marker < buffer.Length() ? marker : B_ERROR; +} diff --git a/libs/librunview/URLCrunch.h b/libs/librunview/URLCrunch.h new file mode 100644 index 0000000..e410e16 --- /dev/null +++ b/libs/librunview/URLCrunch.h @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Todd Lair + * + */ + +#ifndef URLCRUNCH_H_ +#define URLCRUNCH_H_ + +#include + +class URLCrunch +{ + BString buffer; + int32 current_pos; + + public: + + URLCrunch (const char *, int32); + ~URLCrunch (void); + int32 Crunch (BString *); +}; + +#endif diff --git a/libs/librunview/Utilities.cpp b/libs/librunview/Utilities.cpp new file mode 100644 index 0000000..18e6394 --- /dev/null +++ b/libs/librunview/Utilities.cpp @@ -0,0 +1,378 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Wade Majors + * Todd Lair + * Andrew Bazan + */ + +#include +#include + +#include +#include +#include +#include +#include + +const float doubleClickThresh = 6; + +BString +GetWord (const char *cData, int32 wordNeeded) +{ + /* + * Function purpose: Get word number {wordNeeded} from {cData} + * (space delimited) + */ + + BString data (cData); + BString buffer ("-9z99"); + int32 wordAt (1), place (0); + + while (wordAt != wordNeeded && place != B_ERROR) + { + if ((place = data.FindFirst ('\x20', place)) != B_ERROR) + if (++place < data.Length() + && data[place] != '\x20') + ++wordAt; + } + + if (wordAt == wordNeeded + && place != B_ERROR + && place < data.Length()) + { + int32 end (data.FindFirst ('\x20', place)); + + if (end == B_ERROR) + end = data.Length(); + + data.CopyInto (buffer, place, end - place); + } + + return buffer; +} + +BString +GetWordColon (const char *cData, int32 wordNeeded) +{ + /* + * Function purpose: Get word number {wordNeeded} from {cData} + * (colon delimited) + */ + + BString data (cData); + BString buffer ("-9z99"); + int32 wordAt (1), place (0); + + while (wordAt != wordNeeded && place != B_ERROR) + { + if ((place = data.FindFirst (':', place)) != B_ERROR) + if (++place < data.Length() + && data[place] != ':') + ++wordAt; + } + + if (wordAt == wordNeeded + && place != B_ERROR + && place < data.Length()) + { + int32 end (data.FindFirst (':', place)); + + if (end == B_ERROR) + end = data.Length(); + + data.CopyInto (buffer, place, end - place); + } + + return buffer; +} + +BString +RestOfString (const char *cData, int32 wordStart) +{ + /* + * Function purpose: Get word number {wordStart} from {cData} + * append the rest of the string after {wordStart} + * (space delimited) + */ + + BString data (cData); + int32 wordAt (1), place (0); + BString buffer ("-9z99"); + + while (wordAt != wordStart && place != B_ERROR) + { + if ((place = data.FindFirst ('\x20', place)) != B_ERROR) + if (++place < data.Length() + && data[place] != '\x20') + ++wordAt; + } + + if (wordAt == wordStart + && place != B_ERROR + && place < data.Length()) + data.CopyInto (buffer, place, data.Length() - place); + + return buffer; +} + +BString +GetNick (const char *cData) +{ + /* + * Function purpose: Get nickname from {cData} + * + * Expected format: nickname!user@host.name + */ + + BString data (cData); + BString theNick; + + for (int32 i = 1; i < data.Length() && data[i] != '!' && data[i] != '\x20'; ++i) + theNick += data[i]; + + return theNick; +} + +BString +GetIdent (const char *cData) +{ + /* + * Function purpose: Get identname/username from {cData} + * + * Expected format: nickname!user@host.name + */ + + BString data (GetWord(cData, 1)); + BString theIdent; + int32 place[2]; + + if ((place[0] = data.FindFirst ('!')) != B_ERROR + && (place[1] = data.FindFirst ('@')) != B_ERROR) + { + ++(place[0]); + data.CopyInto (theIdent, place[0], place[1] - place[0]); + } + + return theIdent; +} + +BString +GetAddress (const char *cData) +{ + /* + * Function purpose: Get address/hostname from {cData} + * + * Expected format: nickname!user@host.name + */ + + BString data (GetWord(cData, 1)); + BString address; + int32 place; + + if ((place = data.FindFirst ('@')) != B_ERROR) + { + int32 length (data.FindFirst ('\x20', place)); + + if (length == B_ERROR) + length = data.Length(); + + ++place; + data.CopyInto (address, place, length - place); + } + + return address; +} + +BString +TimeStamp() +{ + /* + * Function purpose: Return the timestamp string + * + */ + +// if(!vision_app->GetBool ("timestamp")) +// return ""; + +// const char *ts_format (vision_app->GetString ("timestamp_format")); + const char *ts_format = "[%H:%M]"; + + time_t myTime (time (0)); + tm curTime; + localtime_r (&myTime, &curTime); + + char tempTime[32]; + tempTime[strftime (tempTime, 31, ts_format, &curTime)] = '\0'; + + return BString (tempTime).Append('\x20', 1); +} + + +BString +ExpandKeyed ( + const char *incoming, + const char *keys, + const char **expansions) +{ + BString buffer; + + while (incoming && *incoming) + { + if (*incoming == '$') + { + const char *place; + + ++incoming; + + if ((place = strchr (keys, *incoming)) != 0) + buffer += expansions[place - keys]; + else + buffer += *incoming; + } + else + buffer += *incoming; + + ++incoming; + } + + buffer += "\n"; + + return buffer; +} + +BString +StringToURI (const char *string) +{ + /* + * Function purpose: Converts {string} to a URI safe format + * + */ + + BString buffer (string); + buffer.ToLower(); + buffer.ReplaceAll ("%", "%25"); // do this first! + buffer.ReplaceAll ("\n", "%20"); + buffer.ReplaceAll (" ", "%20"); + buffer.ReplaceAll ("\"", "%22"); + buffer.ReplaceAll ("#", "%23"); + buffer.ReplaceAll ("@", "%40"); + buffer.ReplaceAll ("`", "%60"); + buffer.ReplaceAll (":", "%3A"); + buffer.ReplaceAll ("<", "%3C"); + buffer.ReplaceAll (">", "%3E"); + buffer.ReplaceAll ("[", "%5B"); + buffer.ReplaceAll ("\\", "%5C"); + buffer.ReplaceAll ("]", "%5D"); + buffer.ReplaceAll ("^", "%5E"); + buffer.ReplaceAll ("{", "%7B"); + buffer.ReplaceAll ("|", "%7C"); + buffer.ReplaceAll ("}", "%7D"); + buffer.ReplaceAll ("~", "%7E"); + return buffer; +} + +BString +DurationString (int64 value) +{ + /* + * Function purpose: Return a duration string based on {value} + * + */ + + BString duration; + bigtime_t micro = value; + bigtime_t milli = micro/1000; + bigtime_t sec = milli/1000; + bigtime_t min = sec/60; + bigtime_t hours = min/60; + bigtime_t days = hours/24; + + char message[512] = ""; + if (days) + sprintf(message, "%Ld day%s ",days,days!=1?"s":""); + + if (hours%24) + sprintf(message, "%s%Ld hr%s ",message, hours%24,(hours%24)!=1?"s":""); + + if (min%60) + sprintf(message, "%s%Ld min%s ",message, min%60, (min%60)!=1?"s":""); + + sprintf(message, "%s%Ld.%Ld sec%s",message, sec%60, (milli%1000), (sec%60)!=1?"s":""); + + duration += message; + + return duration; +} + + +const char * +RelToAbsPath (const char *append_) +{ + app_info ai; + be_app->GetAppInfo (&ai); + + BEntry entry (&ai.ref); + BPath path; + entry.GetPath (&path); + path.GetParent (&path); + path.Append (append_); + + return path.Path(); +} + + +int32 +Get440Len (const char *cData) +{ + BString data (cData); + + if (data.Length() < 440) + return data.Length(); + else + { + int32 place (data.FindLast ('\x20', 440)); + if (place == B_ERROR) + return 440; + return place; + } +} + +uint16 +CheckClickCount(BPoint point, BPoint &lastClick, bigtime_t sysTime, bigtime_t &lastClickTime, int16 &clickCount) +{ + // check time and proximity + BPoint delta = point - lastClick; + + bigtime_t timeDelta = sysTime - lastClickTime; + + bigtime_t doubleClickSpeed; + get_click_speed(&doubleClickSpeed); + + lastClickTime = sysTime; + + if (timeDelta < doubleClickSpeed + && fabs(delta.x) < doubleClickThresh + && fabs(delta.y) < doubleClickThresh) + return (++clickCount); + + lastClick = point; + clickCount = 1; + return clickCount; +} + diff --git a/libs/librunview/Utilities.h b/libs/librunview/Utilities.h new file mode 100644 index 0000000..80af0ca --- /dev/null +++ b/libs/librunview/Utilities.h @@ -0,0 +1,70 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Vision. + * + * The Initial Developer of the Original Code is The Vision Team. + * Portions created by The Vision Team are + * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights + * Reserved. + * + * Contributor(s): Wade Majors + * Todd Lair + * Andrew Bazan + */ + +#ifndef _UTILITIES_H +#define _UTILITIES_H_ + +#include + +template class AutoDestructor { + public: + AutoDestructor(T *t) + { + fObject = t; + } + + virtual ~AutoDestructor(void) + { + delete fObject; + } + + void SetTo(T *t) + { + delete fObject; + fObject = t; + } + + private: + T *fObject; +}; + + +class BMessage; +class BPoint; + +BString GetWord (const char *, int32); +BString RestOfString (const char *, int32); +BString GetNick (const char *); +BString GetIdent (const char *); +BString GetAddress (const char *); +BString TimeStamp (void); +BString ExpandKeyed (const char *, const char *, const char **); +BString DurationString (int64); +BString StringToURI (const char *); +const char *RelToAbsPath (const char *); +BString GetWordColon (const char *, int32); +int32 Get440Len (const char *); +uint16 CheckClickCount(BPoint, BPoint &, bigtime_t, bigtime_t &, int16 &); + + +#endif diff --git a/libs/libsupport/Jamfile b/libs/libsupport/Jamfile new file mode 100644 index 0000000..2a9daf0 --- /dev/null +++ b/libs/libsupport/Jamfile @@ -0,0 +1,7 @@ +SubDir TOP libs libsupport ; + +SubDirSysHdrs [ FDirName $(TOP) libs ] ; + +StaticLibrary libsupport.a : + Singleton.cpp +; diff --git a/libs/libsupport/Singleton.h b/libs/libsupport/Singleton.h new file mode 100644 index 0000000..aa936fe --- /dev/null +++ b/libs/libsupport/Singleton.h @@ -0,0 +1,24 @@ +/* + * Copyright 2010, Pier Luigi Fiorini. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SINGLETON_H +#define _SINGLETON_H + +template +class Singleton { +public: + static T* Get() + { + if (!fInstance) + fInstance = new T(); + return fInstance; + } + +protected: + static T* fInstance; + + Singleton() {} +}; + +#endif // _SINGLETON_H diff --git a/libs/private/IconUtils.h b/libs/private/IconUtils.h new file mode 100644 index 0000000..fdcfbd9 --- /dev/null +++ b/libs/private/IconUtils.h @@ -0,0 +1,80 @@ +/* + * Copyright 2006-2008, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ICON_UTILS_H +#define _ICON_UTILS_H + + +#include + +class BBitmap; +class BNode; + + +// This class is a little different from many other classes. +// You don't create an instance of it; you just call its various +// static member functions for utility-like operations. +class BIconUtils { + BIconUtils(); + ~BIconUtils(); + BIconUtils(const BIconUtils&); + BIconUtils& operator=(const BIconUtils&); + +public: + + // Utility function to import an icon from the node that + // has either of the provided attribute names. Which icon type + // is preferred (vector, small or large B_CMAP8 icon) depends + // on the colorspace of the provided bitmap. If the colorspace + // is B_CMAP8, B_CMAP8 icons are preferred. In that case, the + // bitmap size must also match the provided icon_size "size"! + static status_t GetIcon(BNode* node, + const char* vectorIconAttrName, + const char* smallIconAttrName, + const char* largeIconAttrName, + icon_size size, BBitmap* result); + + // Utility functions to import a vector icon in "flat icon" + // format from a BNode attribute or from a flat buffer in + // memory into the preallocated BBitmap "result". + // The colorspace of result needs to be B_RGBA32 or at + // least B_RGB32 (though that makes less sense). The icon + // will be scaled from it's "native" size of 64x64 to the + // size of the bitmap, the scale is derived from the bitmap + // width, the bitmap should have square dimension, or the + // icon will be cut off at the bottom (or have room left). + static status_t GetVectorIcon(BNode* node, + const char* attrName, BBitmap* result); + + static status_t GetVectorIcon(const uint8* buffer, + size_t size, BBitmap* result); + + // Utility function to import an "old" BeOS icon in B_CMAP8 + // colorspace from either the small icon attribute or the + // large icon attribute as given in "smallIconAttrName" and + // "largeIconAttrName". Which icon is loaded depends on + // the given "size". + static status_t GetCMAP8Icon(BNode* node, + const char* smallIconAttrName, + const char* largeIconAttrName, + icon_size size, BBitmap* icon); + + // Utility functions to convert from old icon colorspace + // into colorspace of BBitmap "result" (should be B_RGBA32 + // to make any sense). + static status_t ConvertFromCMAP8(BBitmap* source, + BBitmap* result); + static status_t ConvertToCMAP8(BBitmap* source, + BBitmap* result); + + static status_t ConvertFromCMAP8(const uint8* data, + uint32 width, uint32 height, + uint32 bytesPerRow, BBitmap* result); + + static status_t ConvertToCMAP8(const uint8* data, + uint32 width, uint32 height, + uint32 bytesPerRow, BBitmap* result); +}; + +#endif // _ICON_UTILS_H diff --git a/libs/private/MenuPrivate.h b/libs/private/MenuPrivate.h new file mode 100644 index 0000000..d86ecfe --- /dev/null +++ b/libs/private/MenuPrivate.h @@ -0,0 +1,86 @@ +/* + * Copyright 2006-2008, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stefano Ceccherini (stefano.ceccherini@gmail.com) + */ + +#ifndef __MENU_PRIVATE_H +#define __MENU_PRIVATE_H + +#include + +enum menu_states { + MENU_STATE_TRACKING = 0, + MENU_STATE_TRACKING_SUBMENU = 1, + MENU_STATE_CLOSED = 5 +}; + + +class BBitmap; +class BMenu; +class BWindow; + +namespace BPrivate { + +extern const char *kEmptyMenuLabel; + +class MenuPrivate { +public: + MenuPrivate(BMenu *menu); + + menu_layout Layout() const; + + void ItemMarked(BMenuItem *item); + void CacheFontInfo(); + + float FontHeight() const; + float Ascent() const; + BRect Padding() const; + void GetItemMargins(float *, float *, float *, float *) const; + + static bool IsAltCommandKey(); + + int State(BMenuItem **item = NULL) const; + + void Install(BWindow *window); + void Uninstall(); + void SetSuper(BMenu *menu); + void SetSuperItem(BMenuItem *item); + void InvokeItem(BMenuItem *item, bool now = false); + void QuitTracking(bool thisMenuOnly = true); + + static status_t CreateBitmaps(); + static void DeleteBitmaps(); + + static const BBitmap *MenuItemCommand(); + static const BBitmap *MenuItemControl(); + static const BBitmap *MenuItemOption(); + static const BBitmap *MenuItemShift(); +private: + BMenu *fMenu; + + static BBitmap *sMenuItemAlt; + static BBitmap *sMenuItemControl; + static BBitmap *sMenuItemOption; + static BBitmap *sMenuItemShift; + +}; + + +}; + + +// Note: since sqrt is slow, we don't use it and return the square of the distance +#define square(x) ((x) * (x)) +static inline float +point_distance(const BPoint &pointA, const BPoint &pointB) +{ + return square(pointA.x - pointB.x) + square(pointA.y - pointB.y); +} + +#undef square + + +#endif // __MENU_PRIVATE_H diff --git a/protocols/Jamfile b/protocols/Jamfile new file mode 100644 index 0000000..b6f56b5 --- /dev/null +++ b/protocols/Jamfile @@ -0,0 +1,4 @@ +SubDir TOP protocols ; + +# Include all the components. +SubInclude TOP protocols gtalk ; diff --git a/protocols/gtalk/GoogleTalk.cpp b/protocols/gtalk/GoogleTalk.cpp new file mode 100644 index 0000000..5e8eae3 --- /dev/null +++ b/protocols/gtalk/GoogleTalk.cpp @@ -0,0 +1,853 @@ +#include +#include + +#include + +#include +#include + +#include "GoogleTalk.h" + +const char* kProtocolName = "gtalk"; + +int64 idsms = 0; + + +GoogleTalk::GoogleTalk() + : JabberHandler("jabberHandler", fPlug = new JabberSSLPlug("talk.google.com", 5223)), + fUsername(""), + fServer("gmail.com"), + fPassword("") +{ +} + + +GoogleTalk::~GoogleTalk() +{ + Shutdown(); +} + + +status_t +GoogleTalk::Init(CayaProtocolMessengerInterface* msgr) +{ + fServerMsgr = msgr; + fRostered = false; + fAgent = false; + fFullLogged = false; + fPerc = 0.0; + fLaterBuddyList = new StrList(); + + return B_OK; +} + + +status_t +GoogleTalk::Shutdown() +{ + LogOff(); + + fLaterBuddyList->clear(); + delete fLaterBuddyList; + + thread_id plug = fPlug->Thread(); + BMessenger(fPlug).SendMessage(B_QUIT_REQUESTED); + fPlug = NULL; + + int32 res = 0; + wait_for_thread(plug, &res); + + return B_OK; +} + + +status_t +GoogleTalk::Process(BMessage* msg) +{ + msg->PrintToStream(); + + switch (msg->what) { + case IM_MESSAGE: + { + int32 im_what = 0; + + msg->FindInt32("im_what", &im_what); + + switch (im_what) { + case IM_SET_NICKNAME: + { + BString nick; + + if (msg->FindString("nick", &nick) == B_OK) + SetOwnNickname(nick); + break; + } + case IM_SET_STATUS: + { + int32 status = msg->FindInt32("status"); + BString status_msg(""); + msg->FindString("message", &status_msg); + + switch (status) { + case CAYA_ONLINE: + if (!IsAuthorized()) { + if (fServer == "") + Error("Empty Server!", NULL); + if (fUsername == "") + Error("Empty Username!", NULL); + if (fPassword == "") + Error("Empty Password!",NULL); + + Progress("GoogleTalk Login", "GoogleTalk: Connecting...", 0.0f); + SetStatus(S_ONLINE, ""); + RequestVCard(GetJid()); //by default we ask for our own vCard. + } else { + SetStatus(S_ONLINE, ""); + SetAway(false); + } + break; + case CAYA_AWAY: + if (IsAuthorized()) { + SetStatus(S_AWAY, status_msg); + SetAway(true); + } + break; + case CAYA_EXTENDED_AWAY: + if (IsAuthorized()) { + SetStatus(S_XA, status_msg); + SetAway(true); + } + break; + case CAYA_DO_NOT_DISTURB: + if (IsAuthorized()) { + SetStatus(S_DND, status_msg); + } + break; + case CAYA_OFFLINE: + SetStatus(S_OFFLINE, ""); + break; + default: + Error("Invalid", NULL); + break; + } + break; + } + case IM_SEND_MESSAGE: + { + const char* buddy = msg->FindString("id"); + const char* sms = msg->FindString("message"); + + JabberMessage jm; + jm.SetTo(buddy); + jm.SetFrom(GetJid()); + jm.SetBody(sms); + TimeStamp(jm); + + // Not the right place.. see Jabber::Message + JabberContact* contact = getContact(buddy); + + //tmp: new mess id! + BString messid("caya"); + messid << idsms; + idsms++; + + if (contact) + jm.SetID(messid); + + SendMessage(jm); + MessageSent(buddy,sms); + break; + } + case IM_REGISTER_CONTACTS: + { + type_code garbage; + int32 count = 0; + msg->GetInfo("id", &garbage, &count); + + if (count > 0) { + for (int i = 0; msg->FindString("id", i); i++) { + const char* id = msg->FindString("id", i); + JabberContact* contact = getContact(id); + if (contact) + BuddyStatusChanged(contact); + else { + // Are we on-line? + // send auth req? + if (fFullLogged) { + AddContact(id, id, ""); + BuddyStatusChanged(id, CAYA_OFFLINE); + } else { + // we add to a temp list. + // when logged in we will register the new buddy... + fLaterBuddyList->push_back(BString(id)); + } + } + } + } else + return B_ERROR; + break; + } + case IM_UNREGISTER_CONTACTS: + { + const char* buddy = NULL; + + for (int i = 0; msg->FindString("id", i, &buddy) == B_OK; i++) { + //LOG(kProtocolName, liDebug, "Unregister Contact: '%s'", buddy); + + if (!fFullLogged) + BuddyStatusChanged(buddy, CAYA_OFFLINE); + else { + //LOG(kProtocolName, liDebug, "Unregister Contact DOING IT"); + JabberContact* contact = getContact(buddy); + if (contact) + RemoveContact(contact); + } + } + break; + } + case IM_USER_STARTED_TYPING: + { + const char* id = NULL; + + if (msg->FindString("id", &id) == B_OK) { + JabberContact* contact=getContact(id); + if (contact) + StartComposingMessage(contact); + } + break; + } + case IM_USER_STOPPED_TYPING: + { + const char* id = NULL; + + if (msg->FindString("id", &id) == B_OK) { + JabberContact* contact = getContact(id); + if (contact && (contact->GetLastMessageID().ICompare("") != 0)) { + StopComposingMessage(contact); + contact->SetLastMessageID(""); + } + } + break; + } + case IM_GET_CONTACT_INFO: + SendContactInfo(msg->FindString("id")); + break; + case IM_SEND_AUTH_ACK: + { + if (!IsAuthorized()) + return B_ERROR; + + const char* id = msg->FindString("id"); + int32 button = msg->FindInt32("which"); + + if (button == 0) { + // Authorization granted + AcceptSubscription(id); + BMessage im_msg(IM_MESSAGE); + im_msg.AddInt32("im_what", IM_CONTACT_AUTHORIZED); + im_msg.AddString("protocol", kProtocolName); + im_msg.AddString("id", id); + im_msg.AddString("message", ""); + fServerMsgr->SendMessage(&im_msg); + + // Now we want to see you! ;) + AddContact(id, id, ""); + } else { + // Authorization rejected + Error("Authorization rejected!",id); + } + break; + } + case IM_SPECIAL_TO_PROTOCOL: + Send(msg->FindString("direct_data")); + break; + default: + // We don't handle this im_what code + //LOG(kProtocolName, liDebug, "Got unhandled message: %ld", im_what); + msg->PrintToStream(); + return B_ERROR; + } + break; + } + default: + // We don't handle this what code + return B_ERROR; + } + + return B_OK; +} + + +const char* +GoogleTalk::GetSignature() +{ + return kProtocolName; +} + + +const char* +GoogleTalk::GetFriendlySignature() +{ + return "Google Talk"; +} + + +status_t +GoogleTalk::UpdateSettings(BMessage& msg) +{ + const char* username = NULL; + const char* password = NULL; + const char* res = NULL; + + msg.FindString("username", &username); + msg.FindString("password", &password); + msg.FindString("resource", &res); + + if ((username == NULL) || (password == NULL)) { + //LOG( kProtocolName, liHigh, "Invalid settings!"); + printf("Invalid settings"); + return B_ERROR; + } + + fUsername = username; + int32 atpos=fUsername.FindLast("@"); + if (atpos> 0) { + BString server; + fUsername.CopyInto(server,atpos + 1,fUsername.Length()-atpos); + fUsername.Remove(atpos,fUsername.Length()-atpos); + fServer = server; + } else + fServer.SetTo("gmail.com"); + + fPassword = password; + + SetUsername(fUsername); + SetHost(fServer); + SetPassword(fPassword); + + if (strlen(res)==0) + SetResource("caya"); + else + SetResource(res); + + SetPriority(5); + SetPort(5223); + + return B_OK; +} + + +uint32 +GoogleTalk::GetEncoding() +{ + return 0xffff; // No conversion, GoogleTalk handles UTF-8 ??? +} + + +// JabberManager stuff + + +void +GoogleTalk::Error(const char* message, const char* who) +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::Error(%s,%s)", message, who); + + BMessage msg(IM_ERROR); + msg.AddString("protocol", kProtocolName); + if (who) + msg.AddString("id", who); + msg.AddString("error", message); + + fServerMsgr->SendMessage( &msg ); +} + + +void +GoogleTalk::GotMessage(const char* from, const char* message) +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::GotMessage()"); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_MESSAGE_RECEIVED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", from); + msg.AddString("message", message); + + fServerMsgr->SendMessage( &msg ); +} + + +void +GoogleTalk::MessageSent(const char* to, const char* message) +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::GotMessage()"); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_MESSAGE_SENT); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", to); + msg.AddString("message", message); + + fServerMsgr->SendMessage( &msg ); +} + + +void +GoogleTalk::LoggedIn() +{ + Progress("GoogleTalk Login", "GoogleTalk: Logged in!", 1.00); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_SET); + msg.AddString("protocol", kProtocolName); + msg.AddInt32("status", CAYA_ONLINE); + + fServerMsgr->SendMessage(&msg); + + fFullLogged = true; + + + + while (fLaterBuddyList->size() != 0) { + BString id = *(fLaterBuddyList->begin()); + fLaterBuddyList->pop_front(); // removes first item + JabberContact* contact=getContact(id.String()); + if (!contact) { + AddContact(id.String(),id.String(),""); + BuddyStatusChanged(id.String(), CAYA_OFFLINE); + } + } + +} + + +void +GoogleTalk::SetAway(bool away) +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::SetAway()"); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_SET); + msg.AddString("protocol", kProtocolName); + if ( away ) + msg.AddInt32("status", CAYA_AWAY); + else + msg.AddInt32("status", CAYA_ONLINE); + + fServerMsgr->SendMessage( &msg ); +} + + +void +GoogleTalk::LoggedOut() +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::LoggedOut()"); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_SET); + msg.AddString("protocol", kProtocolName); + msg.AddInt32("status", CAYA_OFFLINE); + fServerMsgr->SendMessage(&msg); + fFullLogged = false; + fRostered = false; + fAgent = false; + fPerc = 0.0; +} + + +void +GoogleTalk::BuddyStatusChanged(JabberContact* who) +{ + BuddyStatusChanged(who->GetPresence()); +} + + +void +GoogleTalk::BuddyStatusChanged(JabberPresence* jp) +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::BuddyStatusChanged(%s)",jp->GetJid().String()); + + //avoid a receiving self status changes or empty status: + if (jp->GetJid() == "" || jp->GetJid().ICompare(GetJid()) == 0) + return; + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", jp->GetJid()); + msg.AddString("resource", jp->GetResource()); + + AddStatusString(jp, &msg); + fServerMsgr->SendMessage(&msg); +} + + +void +GoogleTalk::AddStatusString(JabberPresence* jp, BMessage* msg) +{ + int32 show = jp->GetShow(); + switch (show) { + case S_XA: + msg->AddInt32("status", CAYA_EXTENDED_AWAY); + break; + case S_AWAY: + msg->AddInt32("status", CAYA_AWAY); + break; + case S_ONLINE: + msg->AddInt32("status", CAYA_ONLINE); + break; + case S_DND: + msg->AddInt32("status", CAYA_DO_NOT_DISTURB); + break; + case S_CHAT: + msg->AddInt32("status", CAYA_ONLINE); + break; + case S_SEND: + msg->AddInt32("status", CAYA_ONLINE); + break; + default: + msg->AddInt32("status", CAYA_OFFLINE); + break; + } + + if (jp->GetType().ICompare("unavailable") == 0) + msg->AddInt32("status", CAYA_OFFLINE); + + msg->AddString("message", jp->GetStatus()); +} + + +void +GoogleTalk::BuddyStatusChanged(const char* who, CayaStatus status) +{ + //LOG("GoogleTalk", liDebug, "GoogleTalk::BuddyStatusChanged(%s,%s)",who,status); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddInt32("status", status); + + fServerMsgr->SendMessage( &msg ); +} + + +void +GoogleTalk::Progress(const char* id, const char* message, float progress) +{ + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_PROGRESS ); + msg.AddString("protocol", kProtocolName); + msg.AddString("progressID", id); + msg.AddString("message", message); + msg.AddFloat("progress", progress); + msg.AddInt32("state", 11); //IM_impsConnecting ); + + fServerMsgr->SendMessage(&msg); +} + + +JabberContact* +GoogleTalk::getContact(const char* id) +{ + RosterList *rl = getRosterList(); + JabberContact* contact = NULL; + //LOG(kProtocolName, liDebug, "getContact %s", id); + + for(int32 i = 0; i < rl->CountItems(); i++) { + contact = reinterpret_cast(getRosterList()->ItemAt(i)); + //LOG(kProtocolName, liDebug, "getContact [%3d] GetJID %s", i,contact->GetJid().String()); + + if (contact->GetJid().ICompare(id) == 0) { + //LOG(kProtocolName, liDebug, "getContact found!"); + return contact; + } + } + + return NULL; +} + +void +GoogleTalk::SendContactInfo(const JabberContact* jid) +{ + int32 what = IM_CONTACT_INFO; + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", what); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", jid->GetJid()); + msg.AddString("nick", jid->GetName()); + + // vCard information + JabberVCard* vCard = jid->GetVCard(); + if (vCard) { + msg.AddString("full name", vCard->GetFullName()); + msg.AddString("first name", vCard->GetGivenName()); + msg.AddString("middle name", vCard->GetMiddleName()); + msg.AddString("last name", vCard->GetFamilyName()); + msg.AddString("email", vCard->GetEmail()); + msg.AddString("birthday", vCard->GetBirthday()); + msg.AddString("url", vCard->GetURL()); + + entry_ref ref; + if (get_ref_for_path(vCard->GetCachedPhotoFile().String(), &ref) == B_OK) + msg.AddRef("ref", &ref); + } + + // Send contact information + fServerMsgr->SendMessage(&msg); +} + +void +GoogleTalk::SendContactInfo(const char* id) +{ + JabberContact* jid = getContact(id); + if (!jid) + return; + + SendContactInfo(jid); +} + + +void +GoogleTalk::SendBuddyIcon(const char* id) +{ + JabberContact* jid = getContact(id); + if (!jid) + return; + + // vCard information + JabberVCard* vCard = jid->GetVCard(); + if (vCard) { + BString data = vCard->GetPhotoContent(); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_SET_AVATAR); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", id); + msg.AddData("icondata", B_RAW_TYPE, data.String(), data.Length()); + fServerMsgr->SendMessage(&msg); + } +} + + +// Callbacks + +void +GoogleTalk::Authorized() +{ + SetAway(false); + + fPerc +=0.3333f; + + Progress("GoogleTalk Login", "GoogleTalk: Authorized", fPerc); + //LOG(kProtocolName, liDebug, "GoogleTalk:Login %f - Authorized",fPerc) ; + CheckLoginStatus(); + + JabberHandler::Authorized(); +} + + +void +GoogleTalk::Message(JabberMessage* message) +{ + // We have something to tell + if (message->GetBody() != "") + GotMessage(message->GetFrom().String(), message->GetBody().String()); + + // Not a nice situation.. + if(message->GetError() != "") { + Error(message->GetError().String(),message->GetFrom().String()); + return; + } + + //LOG(kProtocolName, liHigh, "GETX: '%s'",message->GetX().String()) ; + + if (message->GetX().ICompare("composing") == 0) { + // Someone send a composing event... + if (message->GetBody() == "") { + //LOG(kProtocolName, liHigh,"CONTACT_STARTED_TYPING"); + BMessage im_msg(IM_MESSAGE); + im_msg.AddInt32("im_what", IM_CONTACT_STARTED_TYPING); + im_msg.AddString("protocol", kProtocolName); + im_msg.AddString("id", message->GetFrom()); + fServerMsgr->SendMessage(&im_msg); + } else { + // where we put the last messge id? on the contact (is it the right place?) + // maybe we should make an hash table? a BMesage.. + JabberContact* contact = getContact(message->GetFrom().String()); + if(contact) + contact->SetLastMessageID(message->GetID()); + } + } else if (message->GetX().ICompare("jabber:x:event") == 0) { + //not define event this maybe due to: + // unkown event. + // no event (means stop all) + + //LOG(kProtocolName, liHigh,"CONTACT_STOPPED_TYPING"); + + BMessage im_msg(IM_MESSAGE); + im_msg.AddInt32("im_what", IM_CONTACT_STOPPED_TYPING); + im_msg.AddString("protocol", kProtocolName); + im_msg.AddString("id", message->GetFrom()); + fServerMsgr->SendMessage(&im_msg); + } +} + + +void +GoogleTalk::Presence(JabberPresence* presence) +{ + BuddyStatusChanged(presence); +} + + +void +GoogleTalk::Roster(RosterList* roster) +{ + // Fix me! (Roster message can arrive at different times) + BMessage serverBased(IM_SERVER_BASED_CONTACT_LIST); + serverBased.AddString("protocol", kProtocolName); + JabberContact* contact; + int size = roster->CountItems(); + + for(int32 i = 0; i < size; i++) { + contact = reinterpret_cast(roster->ItemAt(i)); + serverBased.AddString("id", contact->GetJid()); + } + + fServerMsgr->SendMessage(&serverBased); + + for (int32 i=0; i < size; i++) { + contact = reinterpret_cast(roster->ItemAt(i)); + SendContactInfo(contact); + } + + // Here the case when more than one roster message has arrived! + if(!fRostered) { + fPerc += 0.3333f; + fRostered = true; + Progress("GoogleTalk Login", "GoogleTalk: Roster", fPerc); + } + + //LOG(kProtocolName, liDebug, "GoogleTalk:Login %f - Rostered",fPerc) ; + CheckLoginStatus(); +} + + +void +GoogleTalk::Agents(AgentList* agents) +{ + fPerc +=0.3333f; + fAgent = true; + Progress("GoogleTalk Login", "GoogleTalk: Agents", fPerc); + //LOG(kProtocolName, liDebug, "GoogleTalk:Login %f - Agents",fPerc) ; + CheckLoginStatus(); +} + + +void +GoogleTalk::Disconnected(const BString& reason) +{ + LoggedOut(); + + if (reason == "") + return; + + Error(reason.String(),NULL); +} + + +void +GoogleTalk::SubscriptionRequest(JabberPresence* presence) +{ + BMessage im_msg(IM_MESSAGE); + im_msg.AddInt32("im_what", IM_AUTH_REQUEST); + im_msg.AddString("protocol", kProtocolName); + im_msg.AddString("id", presence->GetJid()); + im_msg.AddString("message", presence->GetStatus()); + + fServerMsgr->SendMessage(&im_msg); +} + + +void +GoogleTalk::Unsubscribe(JabberPresence* presence) +{ + // What should we do when a people unsubscrive from us? + //debugger("Unsubscribe"); + //LOG("GoogleTalk", liDebug, "GoogleTalk::Unsubscribe()"); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", presence->GetJid()); + msg.AddInt32("status", CAYA_OFFLINE); + fServerMsgr->SendMessage(&msg); +} + + +void +GoogleTalk::OwnContactInfo(JabberContact* contact) +{ + int32 what = IM_OWN_CONTACT_INFO; + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", what); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", contact->GetJid()); + msg.AddString("nick", contact->GetName()); + + // vCard information + JabberVCard* vCard = contact->GetVCard(); + if (vCard) { + msg.AddString("full name", vCard->GetFullName()); + msg.AddString("first name", vCard->GetGivenName()); + msg.AddString("middle name", vCard->GetMiddleName()); + msg.AddString("last name", vCard->GetFamilyName()); + msg.AddString("email", vCard->GetEmail()); + msg.AddString("birthday", vCard->GetBirthday()); + msg.AddString("url", vCard->GetURL()); + + entry_ref ref; + if (get_ref_for_path(vCard->GetCachedPhotoFile().String(), &ref) == B_OK) + msg.AddRef("ref", &ref); + } + + // Send information + fServerMsgr->SendMessage(&msg); +} + + +void +GoogleTalk::GotBuddyPhoto(const BString& jid, const BString& imagePath) +{ + BMessage msg(IM_MESSAGE); + + msg.AddInt32("im_what", IM_AVATAR_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", jid); + + entry_ref ref; + if (get_ref_for_path(imagePath.String(), &ref) == B_OK) + msg.AddRef("ref", &ref); + + fServerMsgr->SendMessage(&msg); +} + + +void +GoogleTalk::Registration(JabberRegistration* registration) +{ + // Just created a new account ? + // or we have ack of a registration? ack of registartion! + debugger("Registration"); + registration->PrintToStream(); +} + + +void +GoogleTalk::CheckLoginStatus() +{ + if (fRostered && fAgent && !fFullLogged) + LoggedIn(); +} diff --git a/protocols/gtalk/GoogleTalk.h b/protocols/gtalk/GoogleTalk.h new file mode 100644 index 0000000..0270b13 --- /dev/null +++ b/protocols/gtalk/GoogleTalk.h @@ -0,0 +1,114 @@ +/* + * Copyright 2004-2009, IM Kit Team. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef IMKIT_GoogleTalk_H +#define IMKIT_GoogleTalk_H + +#include + +#include +#include +#include + +#include +#include + +#include "CayaProtocol.h" +#include "CayaConstants.h" + +class GoogleTalkConnection; +class JabberSSLPlug; + +#define RosterList BObjectList +#define AgentList BObjectList + +class GoogleTalk : public JabberManager, public JabberHandler, public CayaProtocol { +public: + + GoogleTalk(); + virtual ~GoogleTalk(); + + // IM::Protocol part begins here + // messenger to im_server + virtual status_t Init( CayaProtocolMessengerInterface* ); + + // called before unloading from memory + virtual status_t Shutdown(); + + // process message + virtual status_t Process( BMessage * ); + + // Get name of protocol + virtual const char * GetSignature(); + virtual const char * GetFriendlySignature(); + + // settings changed + virtual status_t UpdateSettings( BMessage & ); + + // preferred encoding of messages + virtual uint32 GetEncoding(); + // IM::Protocol part ends here + + // JabberManager part begins here + virtual void Error( const char * message, const char * who ); + + virtual void GotMessage( const char * from, const char * msg ); + virtual void MessageSent( const char * to, const char * msg ); + + virtual void LoggedIn(); + virtual void SetAway(bool); + virtual void LoggedOut(); + + //virtual void GotBuddyList( std::list & ); + virtual void BuddyStatusChanged( const char * who, CayaStatus status ); + virtual void BuddyStatusChanged( JabberContact* who ); + virtual void BuddyStatusChanged( JabberPresence* who ); + // JabberManager part ends here + +private: + JabberSSLPlug* fPlug; + CayaProtocolMessengerInterface* fServerMsgr; + + BString fUsername; + BString fServer; + BString fPassword; + + typedef std::list StrList; // new buddy added when off-line. + StrList* fLaterBuddyList; + + //special client + //StrList fSpecialUID; + BMessage fSpecialUID; + + bool fRostered; + bool fAgent; + float fPerc; + bool fFullLogged; + + void Progress( const char * id, const char * message, float progress ); + + JabberContact* getContact(const char* id); + void SendContactInfo(const char* id); + void SendContactInfo(const JabberContact* jid); + void SendBuddyIcon(const char* id); + void AddStatusString(JabberPresence* who ,BMessage* to); + + void CheckLoginStatus(); + +// Callbacks from JabberHandler +protected: + virtual void Authorized(); + virtual void Message(JabberMessage * message); + virtual void Presence(JabberPresence * presence); + virtual void Roster(RosterList * roster); + virtual void Agents(AgentList * agents); + virtual void Disconnected(const BString & reason) ; + virtual void SubscriptionRequest(JabberPresence * presence) ; + virtual void Registration(JabberRegistration * registration) ; + virtual void Unsubscribe(JabberPresence * presence); + virtual void OwnContactInfo(JabberContact* contact); + virtual void GotBuddyPhoto(const BString & jid, const BString & imagePath); +}; + +#endif // IMKIT_GoogleTalk_H diff --git a/protocols/gtalk/Jamfile b/protocols/gtalk/Jamfile new file mode 100644 index 0000000..9c05838 --- /dev/null +++ b/protocols/gtalk/Jamfile @@ -0,0 +1,20 @@ +SubDir TOP protocols gtalk ; + +SubDirSysHdrs [ FDirName $(TOP) ] ; +SubDirSysHdrs [ FDirName $(TOP) application ] ; +SubDirSysHdrs [ FDirName $(TOP) libs ] ; +SubDirSysHdrs [ FDirName $(TOP) libs libjabber ] ; +SubDirSysHdrs [ FDirName $(OPENSSL_INCLUDE_DIR) ] ; + +AddOn gtalk : + main.cpp + GoogleTalk.cpp + : be libjabber.a ssl crypto $(TARGET_LIBSTDC++) expat + : gtalk.rdef SettingsTemplate.rdef +; + +Depends gtalk : libjabber.a ; + +LINKFLAGS on gtalk += -L$(OPENSSL_LIBRARY_DIR) ; + +InstallBin $(APPS_DIRECTORY)/caya/protocols : gtalk ; diff --git a/protocols/gtalk/SettingsTemplate.rdef b/protocols/gtalk/SettingsTemplate.rdef new file mode 100644 index 0000000..789eeac --- /dev/null +++ b/protocols/gtalk/SettingsTemplate.rdef @@ -0,0 +1,18 @@ +resource(1000) message('IMst') { + "setting" = message { + "name" = "username", + "description" = "Username", + int32 "type" = 'CSTR' + }, +# "setting" = message { +# "name" = "server", +# "description" = "Google Server", +# int32 "type" = 'CSTR' +# }, + "setting" = message { + "name" = "password", + "description" = "Password", + int32 "type" = 'CSTR', + "is_secret" = true + } +}; diff --git a/protocols/gtalk/gtalk.rdef b/protocols/gtalk/gtalk.rdef new file mode 100644 index 0000000..308e03c --- /dev/null +++ b/protocols/gtalk/gtalk.rdef @@ -0,0 +1,34 @@ + +resource app_version { + major = 0, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "Google Talk Protocol for Caya", + long_info = "©2009-2010 Andrea Anzani, Pier Luigi Fiorini" +}; + +resource vector_icon { + $"6E636966080501040046020106023E40000000000000003D4000494000470000" + $"7EFFFFFFFFE5E1DA02000602000000BBC0004000000000009220244AF0000000" + $"33CCFC3366FF02000602000000BA000040000000000092202448800000336699" + $"FF6699CC02000602000000B9000040000000000092202448E00000CC0000FFFF" + $"000002000602000000BA000040000000000092202448800000FF9900FFFBFF00" + $"02000602000000BA000040000000000092202448800000006600FF00CC000A02" + $"06C22622C7562239222E342E2B2E3D4146364441483C50404C3C504A444A4E55" + $"44CBB634CBB83E5E2A0206C22622C7562239222E342E2B2E3D4146364441483C" + $"50404C3C504C464A505744CBB634CBB83E5E2A02024C265928532A583B59335D" + $"350610CAFFFEAF375335543B3B5A3B5A395D325D355D2C5D274F275627483241" + $"2C413541BDA7C2A83942BDA7C2A8394A3F463F463C40324036402A40234F2346" + $"2358325E2A5E395EBF5C5A3F5CBF5C5A3F544053080234313C310404FE372C37" + $"393739373A393B383B3A3B3B393B3A3B390406FE0B4536403640363F363E383E" + $"373E383E393E393E3A403B3F3B413B453A0405FE03453C453445344533433244" + $"324332403240323F323E343E333E3408024D2C4D3C0803553C4F3655300D0A00" + $"01001001178400040A020101000A010102000A0101032021210A010204053021" + $"2101178200040A0102070630212101178200040A010108301D2101178200040A" + $"0102090830212101178200040A030103000A040204051001178200040A050207" + $"061001178200040A060108301C2001178200040A07020908100117820004" +}; diff --git a/protocols/gtalk/main.cpp b/protocols/gtalk/main.cpp new file mode 100644 index 0000000..3be1dcc --- /dev/null +++ b/protocols/gtalk/main.cpp @@ -0,0 +1,8 @@ +#include "GoogleTalk.h" + +extern "C" __declspec(dllexport) CayaProtocol *main_protocol (); + +CayaProtocol *main_protocol () +{ + return (CayaProtocol *)(new GoogleTalk()); +} diff --git a/smileys/Jamfile b/smileys/Jamfile new file mode 100644 index 0000000..5a84eb7 --- /dev/null +++ b/smileys/Jamfile @@ -0,0 +1,87 @@ +SubDir TOP smileys ; + +InstallFile $(APPS_DIRECTORY)/caya/smileys : settings.xml ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : airplane.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : angel_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : angry.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : asl.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : auto.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : baring_teeth.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : bat.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : beer_mug.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : black_sheep.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : bowl.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : brb.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : broken_heart.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : cake.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : camera.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : cat.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : cigarette.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : clock.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : coffee.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : computer.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : confused.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : console.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : cry.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : devil_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : dog.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : dont_know.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : dont_tell.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : envelope.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : film.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : girl.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : girl_hug.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : guy.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : guy_hug.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : hahaha.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : handcuffs.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : heart.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : island_palm.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : kiss.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : lightbulb.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : lightning.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : martini.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : messenger.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : mobile_phone.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : money.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : moon.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : nerd.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : note.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : omg.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : party.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : phone.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : pizaa.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : pizza.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : plate.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : present.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : rainbow.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : red.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : regular_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : regular_smiley.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : roll.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : rose.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : ruler.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : sad_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : sarcastic.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : secret.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : shades.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : sick.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : sleepy.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : smilec.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : snail.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : soccer.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : star.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : star2.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : stormy.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : sun.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : teeth_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : thinking.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : thumbs_down.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : thumbs_up.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : tongue_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : turtle.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : umbrella.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : what_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : wilted_rose.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : wink_smile.gif ; +InstallFile $(APPS_DIRECTORY)/caya/smileys : wu.gif ; diff --git a/smileys/airplane.gif b/smileys/airplane.gif new file mode 100644 index 0000000000000000000000000000000000000000..9abb2b6bc938054f04fd1f225e5129cf83c841e9 GIT binary patch literal 1196 zcmcJO-%k?<9KcImpfJQyp-#XWK#Q=&xr!MwC5Q+@0zoF7BU{6dgphMrF`!ix08{nr7Mz!!Wf( z&QxSc0oVG$xcY++72(U!%XEW_|*oF@@b1|_r!AfHS1CzDA?VG7X-TpLh@ zEQMtiRMWJKp@8TC-VMn?(=;`a1-3+``Z=VRLqZH5$?9QMQGjmZFh7Y-Xu)AqPXXgk zQ%+qZ)9JL#Gq!DkM#-{FlY}lHS<;DPaZnLR1z8Fg$Nc-JnNUnogxsrW^vfiXsT$yjjWv z2|p;Uh7uBJ%t|LA;bFsJMUiqw$j}YjwpCSS@emmggX9BsSl4w53*$HeCIhlBj)rZv z42&%`%CQVh(-3ikRHiAKE;69UK`4>8@~JWg?Uy)|rH4Uo1<4C)FX#k;#}ibLz(b(8 z8JYr%0mUbYlAuAq0?(_-q#+;_jwJ+vV;F`cvs@K{;}jmv=kowynwD+n zv@NYD$+AMz48#j%N!E2k-~~en{qw)^s$+})UU0a;@ojO<>BX;Brd>PBKEALPyN#4= zNA-!OqP<0~`ppY1i&c9^Du!>ZOde7WpPX``$cl63yXMBCuB-O5Ppe-$T35O`KDq2Z z-dxP>u6VHib@h{D#q$GotGiBhLrebBbWe5VN8U$&jc;Dw_Cg{B|JZx>bK&RMa#z4}ed>ALz6xJ>5kZrlV6UsE_g<(U)gi^-E$+I_X2m`_A`%{R#t!g z@riMDvSX3&xO`^9bNt*3`| iRO;^D_w?3{w>r-MJzDIm)B_JbDH*!i*;!EFc=KQGN4Kc} literal 0 HcmV?d00001 diff --git a/smileys/angel_smile.gif b/smileys/angel_smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..8726329fcd3d5756df722550e12009940aacb223 GIT binary patch literal 1233 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 literal 0 HcmV?d00001 diff --git a/smileys/auto.gif b/smileys/auto.gif new file mode 100644 index 0000000000000000000000000000000000000000..c31fed969cff101e5651d4b4549ce5dac5285bd9 GIT binary patch literal 1126 zcmb``i8tE^0KoBI49|M1b*5X_&4$-*p68K8_gpVgbxy5VJ6DC)Xz69xYN;ZQuC6$8 zNPfvLB8LcaNE{Pe~-2Y?18@lU~g}4 zcX!upHZLzPPfkAV=~46f{X(H)NHe*(XxiT1e)sO3PB+D5$t4mkr+chkpebYwWS4Yc zi`z9C-P^ZscXoC*Ha1pQS6{zg6bc7&bA^M$28wc|K>9GVv-6Tbh!%JKMwg|gwSZvf z%F4?8`~tVN9|v~UliT7iH420p!^>9$uKFj46UAf}in@Dr(<4vj?%tCI1%qOVVtswR zrA3}q(eYqFaf2<&sNt*BLwdblF4u=wGO8ZROeWL9!h+FgoSAu*l+>PZg+8jCuCMQi z%4Wxrxlv?RB)RG0Ef&S?X zmX>HViCR65DVBKUlMn;~9FK?B5qv?KAC88|A^F^-cxO`l3#h?VMjVfa>FdMwDs%IB zYPD`_Ypbhk5CprhC1Q9w-m@0(S4BpY5D}z?KsGy!%k`sDeL*k)f`TcG=+b6%8NZ6% zR+VzKy1H#=XIHO(iNSEuXc{`T_WT`4qSWT(i{V8?Pa-jh#R}tad_WLMgl<#1W}YpQ z8ix~qXGdSGEh}p=n|IdNH*~ruO6B;})MH!?Z%CtSZB_eZQalI*WO+?;ULL9ftmQrG zR6V^})0xBQzKUTfm1Eo6W)evtm8#m?75*1U9{2GcMB)#5CCwL5L0EiXabq}%8B^DM z@dk~->|I-1+uYm~2nH%E`9)YB7E4dP21QnaA-D$LY_cDgip-;iCX=sSZ<0zMt**W? znf{TB&|P?A;P&WsWJ<6`vyZ>1DV8)u9ua|EqZQ?jQG>(B;OUb*bQUt{Gp`#41CF>4ua&tO2;r( z#xXenBYu~)aUd3+KEa6*;bK`gLYL4{EXxDwTjH{ZSW z-kPF7$S*7z%>gMwI|pUKl>X7Dq{rVN^H3KoGb*<}5B@lRKVCm@Bqh*fpm+zW1EJ5K zMLO4yN}YzwR%%LDj@7!5da5%W4|k(D+=f)y5+O9%c;OFe07m|qM%or=U)a?rSk$F3 zly}+kG+%xcRs5sH>l_*pLy>~V-%ryP+iM=+xgR8Kj65+X%4vPs7H#Q_F|};4kyjGM z5TAvy3dU+HB8Mg)&-@_&nd(i4z64zvjCT`Sqd{97$*8#iqC{&d1VL1NBnIxICzE05 z;u%M^j|1q2YLE_;g+P9htrKEIgtk<)XE60Do+3ARNgI4Lm_KOx+NMqT(cTqF>c=8Dta#<&eao<`Q#!P$f76c`{z?p^v>$ z3HP8m6(${s3EeNj4~P6Z+c2Q&t;!Q6!ZiF|0g8OkSDq&dq)VfqZFpZVOa`<(LQxQ& zgi;-R4AnsxhME{AZx^Z}(Ec|xb$C;W^3x~_gD{wS=KG=f|5=Xre0Tx0e_=+mw`1~Q zZeeN9OkoQ6@l)n7j&yXGouyeV^1kIOcx7?U-04uwqgc4A} zRkZx#0T|3E%+;AZ<}Zp)5!iI~1KN8h*e z!8U$QYVLQG89#CH(LYa{3PZlkW)Ijt-1j`D@Ds-po2Dd39;PrEuPi;iokaF=63@z| zo)V6jQJ2iDP9C;&p}ZDKUFvCE@6{CRpmcSUJE-Y^K}LQ~k^hx_$bETh>-M&vG|39qe_V=+SR?ULjhNV!gL-;b!X6V8ON( K(^)ojxcvuU3VHYd literal 0 HcmV?d00001 diff --git a/smileys/bat.gif b/smileys/bat.gif new file mode 100644 index 0000000000000000000000000000000000000000..74359692db9ab45473f167dbbf4f02a697410ffb GIT binary patch literal 1636 zcmb7@*;i8s0>*DhuwhXaQE};*P-H8kVG$DsLP%IbOhPsiNJ4UN_6-OzmMy6%!4hRl zQBSLdF$!9RIWu5q4mw2*ws4S&l_-jW1qCZ(3xq{aQH1gj^kKg9J^dcPB{M4ni-WcT zTY;AVu(r0gw6rwja=m@~_Wk?!!^6XFxBJnfMY=hDG^yyQrMswI`6y)XU3kq)BxH0kUS%vwCRIVO*{ABR%U5Q-IV6iI9=I-m) zRZ68^ua`-shYW@*SFTvAsjt5+ za&x{I5{f~gSpDDcobw9{UpF<$6bhAAt1T=n(Cd{NjZ~p1G8hypom{C^sC7lfN5;m+ z&!0cfh9?l>_Y;znrO%)L!ep_qiHWHs5`{{o zWoNT;M8;yFsi~LU-Q7eIiOyiq8LS*$t_TEkc=-&LAe+e~Q|O6F;tLnM z=I7@tOr{(jkHyK^pMcNd@|9|}Oreo0bPAP9u2fR#vLt+dE6BPEJy3 zbY3o>$>vubJ> z@A1;o>*eL;#l@xBS@-&w|6ifkeCX*MHYt^n9=jI9a>lGX}QDs}XH^ix%3>14TbOkA0-v)SURq?8NOBr5_(}UKv}4N7zxpR>>Ng(|-@0 zVhfD)=&&(ci1mNzvBM)9i*cAx+!?7V@B#&h&JU@|qKDCl38!Pe%|d=dw#?x`X)t6E1G5SD z0s-E|O}8G}81u>@XOe&IAOWzMt0W8A^kL+SlN_#EPWaP~$Q_OzE8u|)CO9mxDx@EZ z>;PeK8)BzFFfp+X0>c1DM*!sMvuy|1?||Udn>HqyfMPuX8SoJqjDVgajt50?J5;IX zP@dcNfleD*x}k1ILg7UJIq3%tmC2?RAP_`7#bko6Yk55t{~_j)YryAy_PN<5mnu;j(LRChiD7m_pZ;Bwd{)@6Qg+o^V5E7;q($9^lC z|DO?q&)#d(SA6ze|9!y+(}RrjjoAYu5Mugvod9BQM||rWH;7&IjUOV%(SQIC0&V|8 zp_P{KL`U*C@U(PsBlek%v^h1%LV$Tr+SzpAmnJJc@sWQ^JwJHQ<*7z0F~}eI+aJI4 B+>8JK literal 0 HcmV?d00001 diff --git a/smileys/beer_mug.gif b/smileys/beer_mug.gif new file mode 100644 index 0000000000000000000000000000000000000000..b40e13dd7ff545cd9e7514a6d85171283c1eb9a4 GIT binary patch literal 1277 zcmWlYk583V9L6v5V0Q0rTOI4&JkujP;>lj!Dc|x$ul1Vm@-5%&v`%)`?ehmb`#zsN-<6gA zWluIv^Gx&H@OWfwemLCBXcMBpAiHw$x@3)3O}1R*)@>#xY7bs9vBDqmZg?5X9ocVPTcq@gPMBAti@? zsTKmI&oKjxK!Y)k{K-7wRB=@5vapVaIV(kIR4M_ARKqY#rn_bWs!#FT56e$C(-Jt4sFM=VKWESAhDH_W5V!q7;>#3!Pumjqk73oIb1DZ8-!}I z3B?gj?Gvaf9v{NmkgCL_=1s)=1dA}L6BtPO(IzSx|*k_qKw-nP*1#TrM zVj7fDMUYY8c0rz(S&3^+qR{Yj^mi7Wf%-Xs1xG4u4Pn79@HrnsEH@<5w#c-L448)#9~nb znjP0Q8Q@y!Vo#F)f5DR}J>N_mJL&|Fm2ND2>$&sQ8>V;OSAg1m+h@hzY+%23zMFCJ ziJI&J<$yo^>-0I(!JR*>6MM32+I^F@-CUDosXJzW7~h<~;P_X|SL`h>#GR>d_rj9=E2Bl8ij&W`-%}QXE%~4L8`a{*G|%Xs zO@l|yU3&HA#KFl|^4pe-oavdH`N(4%Do383Sy1sg*p#31!gxcDu`KW9&<#9P`4^do zUr)JspsnlQ{#EGa47KqyrQpE%tZQKXjfU#VHNG`pHg~A!qQ$@U-dcaTp`>$P&x+lz z7%y#nC%1iNhHq!f2kj@nYYpd&ow{CGmz!C;f7S@;IDM$E^62pik9IVVKe+#?C2++d z??XT34!*Hxo6^~Ex46Mq)U@OFlpHauV9Jv6w;Oh({(j=s4DxP|pW)yRVOI*ezlgxP0lU&SwxOlv8@6-RiU;eLW zZ*cpL0k6mF`NQLBUf~Op94qO%m8r^c^JtXL&J-Xl%5b7PUmPEoeLg5oQXHF{Uns(@ zkftgNg<>QUf$#!?u%8CK*{ZBuR>qj1NR3k#M#S1K&S1S15S5($EmWijWv`I$LJ)Dm~U^s0VhOSE@?>bIyW?ogt z)21Ga5Ki{CPx3O$3z}g9em@bX=L$u{k6^733Zn^{Vv@-uo%DkUj^RAV1@Vv%Ky=M; z9G7P~Syn95NHHwrhYO`j#!fQ{MiNDJT!tYiZRw&Q#-jZcS?$6{!VjBStXnh1;Ms05Q(_?d77ePR7w&B7=lGX+T^L~ z_7*%170HCT?hczPqNd}$yH7V> zTt8a7I&#oRl_!`!7 zap-l)*FvLbeqPj3zi$1VU%5N4-0BuO7a@tRz_FX&Wk8G6bZx5f*Y^HH_X2hC;`Efq zGyPGZq2syB&(}iEC+%Z1+)9V`x15+A+Uh)5tONS?oZ8(1oxC0l ze9?dD`__0{`=y?jmJfQ+n|nT}UmX~2dt+qP-KSSJeKXrOy~Woy{6y=%yB2f)ntwcX SYhJ!F`0f7v*xDw~1OEeW)Hp@} literal 0 HcmV?d00001 diff --git a/smileys/bowl.gif b/smileys/bowl.gif new file mode 100644 index 0000000000000000000000000000000000000000..1314e9389a929253d8645fbc63714b41997fd654 GIT binary patch literal 684 zcmZ?wbhEHb6k`x$IL5&6|Nnmm28R0jdShebvuDqyrKSD+`BO_v>;C=wmoHyFcI;S8 zOw9cG^CwN3)Y{rwSy@?ES65zM{^-%8t5>fsT)0q8O>O=9^@|oQnmToAM@L6>b#-1| zUQ$w0XlSU1hsWW=ho3%udgI28ef#!p+_-V+(xo$I%;@g!E-WleNl6J051&4L`jsnJ zzI^%e;>C;f^z?%V4{q7AW%=^uvu4fe>+5T5Y@9rK^6c5O7cXACdiCn>-@i|rHf`R# zdE2*d-@kwV@#DwOpFe;7`t|3}pTB?q{^iS;U0q$PR;}8!Y16J(`$@fByaZ_s5SP@7%d_>C&ZT%a*NMw{F|EZRgINyLRo`y?ghbJ$v@<-Meq! zzWw|6@95E^w{G2f_3G89PoIAM`n6-njgjA}W@+i}Z)ag{nLf3* zb@t2|%@gM_ur6J;d}+sW1~zsMPA+bC9$r5F)vWCTf zGAb#nsHzF5YiKUhTBgmeqsy+RZ(wL-Y;tO;shPROiuXI4ESDNvSsRMk*xK1Ua5y>@ z@gy0tIBF{Kro?C@J>i(7!Z}4J@zRl#lNACM{WuZ2;2xi5@QRLrfTO2Gbt1Rq{5<&7 z!zPGR+^j}oX*Y|0{DBt1&y%LOPf+rl<+4)9*?$I?q?J$5=d^Q+o468wNED@)&Sqj{um%9Jq=Kyg literal 0 HcmV?d00001 diff --git a/smileys/brb.gif b/smileys/brb.gif new file mode 100644 index 0000000000000000000000000000000000000000..bd4465ae160086812f3edfa32bf963de62a8c58e GIT binary patch literal 5169 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 Xw#}CtVC~o|+DA~6viRQ}zWGph{ z>=B7Q>8wS|^lYOR+cRa3ZCtR9CB!gC9LcC-&U9Q^Qcp9okcBN=aPe;6{*66XZ{9q~ z^LxH8@9A#iiIbOPm<)S{VNtP|bvU?CC=rj-Hd{KKrj5pIHp{u)39&fS)&{xlsM8sV zMA9~EY-}upzhs;&Gm3 z%N|dmP{@;Hu~>w@K2T90&7=WVXtJf5RY*hO%O$JA&|=|l?t!{Uac-` zwKsp{7$1@Ix|DF`I)76EvH_YN>cUu$=|9 z3N&g!DboxDSqb4xa!7hmctFKs^Mh8tR{?#g0Hzyfbn!I)V z^S*tNh2`7+v1HH$2Cj(~Z78GO=!~+WWvXSg5&j z)9M`{9D-`NKxkjiK zl$&cEt&gu)t1i~j)$(S;c$dU8L``A`L<8UNzx>cY#Y~w5UDVxP9Q&}99H1NY62lqh z=IW4v8oqhqen+ct?YesLtGsZZvevXV*SYeQl4dby>s__=|PV LK7Ef6Vz2%S&}_+; literal 0 HcmV?d00001 diff --git a/smileys/cake.gif b/smileys/cake.gif new file mode 100644 index 0000000000000000000000000000000000000000..052c66fdfc5eb1bfdba9f852e236fb7f93c285bd GIT binary patch literal 1232 zcmWlYVQdp+0EWBLe2fFmafM@!?_^0%d8IQtMWs;AR?9lg1vdWjZJ(T_{16^69Jt zm(sR+yv8ftbjJ-Qp}8Mg2LJ$(PD6uilgVmGfS{T4w7$JyQqaxQ}%9e2$P+f#^0@7^-yIM(YmUz0D%RnxvWZZHe z$k{N+n4rY7=0>3h@Kh^|s!^pN^9kOEBR+)~3rg!@g+r`W2$Gx&l-Uy^8;41oJZzzj zfcFz}M3Z&3NUT>GBv3A-WW6ap;5`5_MkGIAOrS)O<#03SBT=#$6(TU>MYI74Y|%}y zW*nsrSsRc-0J2?q7a>Opmn{SWx!yqf*2F;#q)N6 zBq8U*AZstW7c&-I@B%TShvf+|<*o*Cm_G_jW3&lJtf?Me466c+x4^V1XUFAwjrZU@ zS5S%(DH{nl`q=WD2kPQ1gdc5q(=&3B27tQT;WqN z>qBxaW5c0T=G<7$u?#9QV{Srm649278Hiz$_cbHdRdC@YKUwwyls1+_BxG%3nkom$ zk{^fJo{|UDLTZtrP)#iLU}yoxjA$cDkdQXPh0L1M28=P`S?fZd;ygHv0^Uc!3eUMg z-o7w`qgA!Q|6fowBGsQubX_;bZk}$`lDfXVzb=cW_DsCkwkI&Y{n_KOS^3D1i4JS) zAA!Kp*Os@hHJ-ZKyRZ4`yB&wdf1dvG%tf8LeQvHn{bu`NKz#c6z1o?L2j~3X@1U#V zxz=xtouln{G?(_BJwI^pn0ZCca?f#0^>x<=>jM5mYi#4Ums(!(6CeGq-FRoQ4_c>pUj6!QmxDj7JsjJ;+O;wM%9Ej?8C^?c zCZJh2vNG`2if)y`wdK;e{&bX*y@^ik!?uaemFi`kQw^&+x@Wf@aE?ti9MRt>f)&oD!ByDw3y&_=H5%2f{{ZiW BcANkJ literal 0 HcmV?d00001 diff --git a/smileys/camera.gif b/smileys/camera.gif new file mode 100644 index 0000000000000000000000000000000000000000..9965647adab6193e109960c04cc35d5097c04b25 GIT binary patch literal 1206 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 SDpj$f75QzvEc$;ywEZ75Aa#@g literal 0 HcmV?d00001 diff --git a/smileys/clock.gif b/smileys/clock.gif new file mode 100644 index 0000000000000000000000000000000000000000..04ca3d4fe4ad871b3a2eac7d669754adcd925fa6 GIT binary patch literal 1228 zcmd6m;Y%BL0EREoI-^$7&_)+D>M5y+ReOUhwq1yERt;OWh8l(p+k_fiaL1OGW6f-4 zqo$kdf&>jUb!iQ4*baKgwFDNrFjIHKY=(M_V?D-EuI?uJaEvQE#?k$@?7!Ia>HYM+ z@W4AfdfL+O(L;LZcL-9e)rQk}4@L!J1%e=oMZuMmSQ*sU>!M^1K@glO@-pa&FI{O6GW9PGopV24FnNMj1I*0%=x`rHO(F0*eKE zipP=!k>k9S6iJibIAd^=MG5!<<&4+V*ZcEgC`s$h312en3>6S39;C!9!)19H@#SJE z8s`->l+zo-W-sX_1(P+2QKAnet>ZW&fds4MavT~j8l40h$HTOoAXvC7ssLb5ux4wV z6hKA*Xo`s@3YmhCF9Bzg^%o@liG+(3s%nB=ZX(4g6kS3KlGjg6E3>wY{%7vNI1SJtvF)Jv9prm;vRFn+HFjkaP zIl)IsA*y8dWlbmryGWW92~IXmWRo0Ft1+A}@1_U=L>WbIj9^sRfP^I&XSnds|B`N~ z%zs~issS{nX|iaC)-0XXUGG-Utv0`L!+pSZ$xhqDokq>`BVX^_JNrKTcb`;xG<0~x zwx>PPUU$Fulg3kL9tq2%*LP;dHrqXKUGF{F__QCovv^eZ>H(x;V1BbjqXRF_%)j)b zu61d7r5e#jHrxwq&ao}qes|^7sivD7>SdSetD0uZ?C}2M`-8!mQv0=?rmJsm+0@~? z8=i-+m8N;m?22)$GxTueV#Ub1{T<&ETi+dB?_>bm-CWuqTs!y8Ok--MJ-=`W>Zsw-dksM7wEVfM8c@wn%s!J`*`UcWY1apePt4%Q0G zwNo!Xw6(oA4OP_&hdQ3M_MC4UsH@Pz17qpeReN^N%+p29WsB-3s!?mv?hWB@ d_YEUxhrO=y3kw9_sJ-&tXZmwJhqchje*u?0z9j$v literal 0 HcmV?d00001 diff --git a/smileys/coffee.gif b/smileys/coffee.gif new file mode 100644 index 0000000000000000000000000000000000000000..3edb55214b9e75a7b7982b1a549bd75a517b75d7 GIT binary patch literal 1144 zcmbu;i!<8?0KoAdLZxWqF}01h=V;Novtf%)cP6T=C_{@m*O9rN(z1E==17@G<5g;n zi5z~>wHlI0gd$WWG>Jz%l2GvzLC7!SaZ%40YyXCQ{)X@Oy1y^l;}=W75?BF%b9gQ|;|MU{PPTym-N4(1wSHAP5>78YU3PwYAMNGjfGu zh2Gpm%8h@X?n{VwExGq&tgmD6RVP2p)%ahr0|Ntmz5tJZrqyaECub(cgxOKAy+W6W<~$ORX3OfDmFH2adDB$74Gb8OU48*iDd<8 z*avq)?%WED3=c_2NT{l+qSNVhb#+-;1tB5#OG`;yE~qLUj7%6*vMkB6BF~YvdX2>g@J+5l@+Bzq0neF0)e2r zyPL^mHZ?WX*Vk89SL5+zg@u)wnfU1FG#su%C>&=p`vih9sZ^>~t2rD_dwV;TN+pxY zL?W@cxI8lQL1JQVX=!a+Ten=ku(!9jy1L%j$RLwxY<9m$BkMdC`PPrrlKll{sn>j@E&4c|0r_Op6&4)A~bj=;Y9R8-` z@{wm;uw(Q`7`wm!TnsMg=1LrYb%_dk(qNe8)u3cEGa|Tx7CMm z22HFzQq}Y0aj^Hf&$9ufE!MEY*0=1uKgi|w+XvL3AL`oUs~p2#MRexsU$e}QYEOn2 z6h_r9v4c+>Y;5zE57w9%&=VszA pj`-c=oA-B_Cf`DtTO$sI&WIrNLJ20wW4Sgj=!(jxI@k;N?mwG?pVR;V literal 0 HcmV?d00001 diff --git a/smileys/computer.gif b/smileys/computer.gif new file mode 100644 index 0000000000000000000000000000000000000000..c4313427304ec01ab1f51d7aeae8cb74ccc150f7 GIT binary patch literal 1219 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 literal 0 HcmV?d00001 diff --git a/smileys/devil_smile.gif b/smileys/devil_smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..2933a250dceafae25728b2635cfcdb4cc4e0ef1e GIT binary patch literal 1115 zcmZ?wbhEHb6lM@+c+SA^|Ns9_A3t0@d-C7Ezd*2H?#vzY=luTt>-X>9B{AWbc5eOq z@9(#7-%cDqc69fSr}yubdb%90Df#v5*Wtql{gkEl&7Qn##}*4CJr@<3N)7oQE#(p| zwGFy*Pp(|tx^=6jywq$>iD{aWsfyxN>eA~{L-rSk99>Ye&`Rsoof}`jehm!^Rgsf% zQIt$l5?`w&ePn6J^IHoJ_GK=tj(`2)Szca_q?AOAqWCUd=_89;N^*ljjddK=6wj?+ zb@VIeEFiSqhl^FHCavKppN8T zE$K;Gic>We_Cy7p+1q&Y^6roCU!6X6N=I8eLQN%CRjFM?w$DIgS#!hfbH}dkkGpWF z^ZDb8FQ480^Y?FZVnUmS(gY2KUJa$27tS>L2doX&xpS`j@{xw?r>6e=@$K!~HyR4^ z6LnQr=*n+5kO|S%^wQE_Z>0YE$>ab3z~KMC8`rN%OG|p`X!Yu;oivtj)m3RqOuTt$ z-`{`#K74pDCnuwzsOYAtovy8up{@Du)vME|Px-mZ;M0MKYsjJzkW+v zUWJoapp#qh=6QYhkFB_{d*hR+o!SJ6!hXDvcnT3Jl z9|I$Yh=judhDH`H2@8V_3msTEMRXD_95~3#A*f;@W6|iu$}Mh?a$!TGb9*n7Z4HB< z(-96KRi8NyjY1AwqS_H#3O+Kq@kknH-C7cO_!zH@WyzZdiXsmD^7aiZf<`SKg39h$ zN}h{SI47(5&2#8fO7-&93SAR(aFXk3F}>J5HIAHWJu?hbPR+1vR_mQ*s&R8m;b%5K z8O!1qS2h;2tIo5j`u5@FhquESi&+cuvuh zEy;K(w9IFgS>dZEFNIeGEOMKurF!9tX2{BrwMkb`UDb}*m~wVe=;>>^3_FTm-a5K^ u`ug|-O$waSZfj<2Og_QEuwk;#O{284a~LH)tP$CgaY>JtfmcC+!5RQf4P-|E literal 0 HcmV?d00001 diff --git a/smileys/dog.gif b/smileys/dog.gif new file mode 100644 index 0000000000000000000000000000000000000000..8a414db6c885c394df1db5c3b9cfcdc00594e28e GIT binary patch literal 1179 zcmWlYVQdq17{x3XFSM7PCUY4F6NEL^Yu-h{NCru z)3+nq_1tR#Pr!52<7x5vOyo0A!V#%>G*Ha9Skh35ra{eUvLqElpk)=BkOa=ub#;co zRBkdIonaUdf~IL2!h~EN2Q6n;A|^9rSr*E7*tMWu_VFVTi7V@xW(wW5STuyR&E{;| zHkgo*is<~fTu9lKm|W}zp`*rEG&W^b>QRXT+yTO9l}={7*Rwl7eaO=sd6zu z6F5hL*d&)}WhQ2Dp&H9rC=CMXR6A=0QsYA4N{ENsTP=~W*?_IYZK0s?6Cl*rN=d-o z%0vQ$G@w@C!qQA0IMT*x;P#n_QrR@{OC3BQQ>0j=4OP|4IlCGLo&X%QaZ(j3HrFh( zCD2mU5@n%)!56h!)sfnP8#GYNo=H3Spe;r~@B!cIuyLi3aHN=p;||UNZk7=XT*Sh8 z5IRjv$Q4>;#{oxFcBn>WEgV&NTII^XWtdV)VuIF80{ASTVL(|G&6&cuBM~+(01g<4 zR4RE3m^^8xfyYDN>gu+p-KaVhEEe z=T_rFx?!d)RCKB?cF4wATa1DbaB$wl-QY&VRX_{@*Xgh+N9;B<&9Q9|DXEll@TgKL z>WU0(C!l6vhfKq;OcVH^F3WN`tB9h7G9b8yiH#mt54Pa(g6FvR$^H|+Kk@QDZ+LIl z?B^dW`6agHv-JZFiyJqzEu6VJu>Is4y_e?yxOlyeTK8LVO6VIu6FIb*nbwjd(?fqh ze_=Rre9u?mZ!Vlwx*iW)^1WmKSH64qrFHQW8Di(`s@}!1!O+e-gD^&fMVb~Medf}v~l zJ$)Co=;-?XseNrf=Nr$JZWmgvOh3H_9sc23ax*pE;PGzRam2H@CwsGL*#`aA7mHr~ zjytsH6LL3QpILLS{-;cw>A2i~QkmOdolbwK{d@7@hN*N(!ctE*Pp*~oT>ZU-_ZQXt+6)$#>2h;9PxD@*go~>>SG75t^IQ+ z(Yqw_BRTNc{W0qW|5I~k#6W!T;78u}JNbTc(ZY>#&!_Xf$;Oe{vxSCDE6>(FB>eSy ZW9#`Fr&hmGn!Enq*4y)I2YNj{{{t|@r&j;~ literal 0 HcmV?d00001 diff --git a/smileys/dont_know.gif b/smileys/dont_know.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3eef00bee09f72f019d71478babbae90f0b3644 GIT binary patch literal 2051 zcmdUuZA?>V6vrNT4eHeptw^*nM2c1h zg4kh$NU+wIY={+#cBXS3qE@)-l~uj!-ExOFTCwQO(qWU`WRJVsN53vH+wBmn1;wIWGihoDTq^ia5gVD1!iL_nLLA zvy^Gq@jgIo24Zc5K@(ue0X+o$3~kHwd2)D;LA1f!3_+Ik=wyB(fujI1>6~4VQUys3 zV$3K&(gx{3g$f~#s0Mc>@GPK!J>UedUd7WZf;Jgt(jYDa@xXh*XHQ|e(s{O-Y+mGZ z>74n1IG{{Ii(;k=T%|Ii41!FNrxI9~h8qC3OM?*dHG|KQjwq!Qmmps!(EtGtAfJ)c z0clo|)qvc7Y3JNZw_Z-4$w#z`G7J1h z!UViujyynA018eIxaBCwFgBnXWQ+v{iUqp_>>{dChJrxrfvgZ*(jm^pIc3N#MVyo; z1qK0LhFBRRsCi{xBM>z*+M)_Lr0ybtKf{BA6PHsK9owlxL5~Ml`Q5^pGP(iC8VK5y zoIQi822ZuXuVU>*Y$wnb!6ku>@fpEg3;~CnbAY2vf>`kCfUc4H97#MWLyQX15~^9~ z0!|&UHt-6Bv@zh6AYS5gWFi*#=z*$M*-HV@O4Trr|x^ zO%M0^Kkr-DZGO31eD2SSK~sUcWdGTk^WpbQt4=P<&EK2!N|bmYbY@RsR&s<#fBl`* zTeGvIlg4Xjr}Vb!b40m=!{U^Wsz%EXn6rBK9k{edQ>%8gh1^s%#trKrC1K=7_(DB) zO%ytRTm75~!|J*jnd0Z`LGePp_Y~@f&3BIfs0jZjYe%9+waTjQg4=1mX^HESPj?hvnX>3Y?Zn8K zK+E39%?tX~vywN|-+V7RBCc`T?PPO*!#uG$BoT}5sc%qV+pnl6D|A{&8y{UiEo;0D z3ttj7Vh%6bJK{0trR?sHQpY?$oV-I}8;G2}VRwJz&%0^EdBrGUSGPI?v=X&Ylly)eeDUXLb1%@10s(0771kczqTjbyNx%xlR@6VX?gZw4t6Av#K%77G+dF?t5e-AQC| zz^dVEGS>=YF(nod)oJpgV|l9SrA0yv*9N|K>}1pCpJ|u7Vu(ess4p1#m1YtqSvA=b z4&+(P`4Q<{nG-RUj9hzHorf85n(0npTMR5(sX7g$FOp1g=hcbI94ODzmY-yeHpH5G zFB5$d5$_Un(9dV}XD|%;AQOp(`VS?U7_a+ysCq{;2b%I=@^Bq#z;F&a5*U`+x5!xZ zbLk#Kz0Z<5yg9+H?g*aT-a;P2Sc#U;(ZhzNZavWl5hX)^6?YDzCDoaTT!;|HYCMRB zBo4FpsAR~Kh|yn&yI)dGEpEo!XpTZR3$u+BqNWlBmPAB`V#5(xH==ohuNq&Vov5s44Uad&Aj3?fUUAHiz?lQ^nUG z(Y^MUg%t(lGW)|_W=s)sZ&+N%&7PmLBg9}+~2~!T@t$U z&%Of1HP5@!aXaPxKT6U>*^WDSpM7w%h9Y;U`D;YvyM<4ZHpWKn}6S literal 0 HcmV?d00001 diff --git a/smileys/envelope.gif b/smileys/envelope.gif new file mode 100644 index 0000000000000000000000000000000000000000..fe54900527aeda9796c664f2c31c6b024abfba59 GIT binary patch literal 1151 zcmd^;+fP~t0Ea=G(q=Z;IBG8sI<2#&NllY=TjrLE)@tfDH+-mZF{oSBG)vFOx~g#* zc&k{k*iJ=74S07^VNwMZA&1Mb!ayW?2*R;)5v9seC~}L={T=(Bf8X2hyPK2s>1V}w z6dtvWLY{<^f#Lm%3eNJfxwlugumFWZ$39;WLHzywGQ0iIVsWupG74pKdRnK`*Z-0DGnsbYzI8u*$RU$Q%gTC{O5@X~(|vt%5{WrB z_P0s}cXTXxJigNd{GYjwI_19>P}pM>8ha%hAfeD0Y|QufQ*Wa&k+{S>3GgN?BI-&S z1(y!iH)F2la{)Al^8Te;fMb)r6&VpnXo|%ahttj{eSJN%jUYdZ4=)r{q7xchE{0d= z86-@3I{p&?P_j!SpHsi636Xr5Y+QUs6Odf;!)A2s4Mrk06*u%E@*dMszGXcVL;ZFT zn|rh2Y!v?EJNZ0vL&gV*_x~bYy_wpG4^bJk-y#CMI9wPm z`gdl`WLRnI<=fQoAEQ3ZR(=(6q2U*Pafw5F;c}BX@jE^c9ha4m32A>Gy4Rl7niiIG zr!5=IjDL_zpv9B&OO~#(sP#EX-GH|KTo0h5eH0hvIg^}O^Clyi)1oU*AN)f{xi-QQ Q;8MOB;A`4~oc6%`1A zVAu~{0Nd*=muu@$|092Y{{SMPy}i=~-~`wLSXxxU}G0H z+_1R|Hh|XvPiN+ahK435CbU{@L_`FUNR-QEe^_=byRhPfH5dHrhF5MFHckya9((27 zHBS6$F!Tw9LN1p}r_+_n+uhj1XX~)+f|V^;-GZL`ec$)!H+H}Q@Y9fyP7lZ9@xH#k ziHV6fZ(LWYznfY0YO(%1>W<}2x7`b=8Ry7k5`jQyX=zDFNGQ4_s#7%I{#Mhb?pSkx z9l-8^7dFT^{b6V*l}I2QU@-E|=N5`Cnx3t0y1}{&zb)Id&*ogYT0Up7UnnXe1qZR& zY%+?rwzm5D`SEzX{QUeHS;OL{XKvLY$jK|eS-a_hH7AHmzhW^X`|9$c2*M47feJU=kt8d-`D7sR5IPp+PNePOgd_F%d?UcAgQhr^kRH@wn3+s-n zk}sK&5iAyKdU`r6EUa)Zk?2xk;iAR1XtCa?tm1MxbGg-(xoyxtz2ZftBUDk@5&(R6or|2Qx(Jp4E#BO@jz#$YfQjYfe$ker;1 zVOUvNnaO0@WApzgc2D!(2~-5Zdl4L-foDpkxP6ou22DC5^}&Z_1r{tJ$UXuqi=ivP z)$aE_kRUetZ9jGQ}u=gTcFIwT`|_CE-%*X(`$|1%>m0E_YNb zds0pMXi!Q%@g$J`mUv;L<-|lY{tV8#{_<~sB{Nk{;$A#yB(pPF90k{EL=R@)O(OV2 zH>jcnyt^8-t0DAf#1pKyl}A5rN!}SheVUKa!j2be)#ecP3FCnr}QJAEeuvu zE+h5Tk~OnlWCK^q?#!@sq#C_1{bpkfaKqFSx34N8`yRR&=jQFL1WiWyN5wULtb8 x-|o+NpkkXtAC926Vhv_{R&7vn?yb0iCA2{9D=f{5kE}VWjQ_>jclJ2)&VP4=lHdRU literal 0 HcmV?d00001 diff --git a/smileys/girl.gif b/smileys/girl.gif new file mode 100644 index 0000000000000000000000000000000000000000..42e57500d2008dcae84c05307279fe5de1f82a8d GIT binary patch literal 1144 zcmV-;1c&=aNk%w1VHN-u0OtSz|NsB{`}^P9)Z*IE$HKYP&Bfx|(d_H!{{H^;^z_EL zrN*+AD$QU(!AEUmcpTY z-PqF7&cVZ_SKF*h>Ah&_%8cR5pWVly*SwU_s(#6!bG@gH^YZZa_V%%)c-XT^?71}Z z#ZU6gX6(mg*Ry2Ls%*}uZOx@{x|nO}TLGrPu|Bp(z036uwApLlIiE$*2+`*>N)!DO8W0u`tMZw z?LzP0IMupL)3jI8vRb*Zn*II!-q^O^&`kR1I{N5A`shFV=s5S}G~LBN)VEO6wN=N# zt@!u#wyBWAr99`!G56Xv_1HAr#5=pIR?xRh&b3qG-p=&%^TCa-@RZKhjikPHT(*IW zzK5sQ(A3Afg14ty>ge6s%+%V7z4xEl_NC18m#+1z-Q$_d%(len=;YSZ#`g8|`S|(G zrM~Qu%lD_;_OICWtIYPZ;q|E8$BeS(-{bM?@63d;`JUMKuiy2pyYh&G_P5~nu;A^Q z(7l_m(Z0#)i^ch;-1xWR_PEXRjfeHS-}kuW_^939i@(ys%)ykf`I^@GuHX2+<@d+w z_QvA&$m#dL=J>GR^OexaleF{i@xg|x`l8zTwBh;1==jd;@{yJEpR@PI>G`+f`k~p` zezx1n)ZgCU(TcYDsoeRx7+sonXJ(z%eS?Ca~enXJc? zwClFn^ULS+)$8=k-SfrQ^w8?_!Q=C-+VYpsvxTD8)X=P=qM(wMospBPo}{gxrl**m zr%zq_;0&BgET>-+oq|NsC0 z|NsC0|NsC0A^8LW3IP8AEC2ui02Tli000R7009UbC@_G40R##dIDmklLxKquEMU;U z!2<{p9zK*XfkFif7cgYduz^EEjRHG(_y8h=h!G@8m^gs~C4dwvR;^mk|TG%9ybU;0&5HYSyr6h)^Lz zhY%@Fq-YVNMvfjqiX>?gUrLoMUBZ+}(#Vo15S0+QAQopAzqsMFb_kx=oAKf#i3lxJZz1Bgumx= z_??$?Y#@2y;H%9{Gjo?=gz=Itr(G-V8VLkBMVh5Wi{OOox_qAXJdYS7mM-IhF7sK> z$PnULh6&0A4C6R0W3%jN1q1+8O3+k;AVAPSc@;}g$#9_)cP+_78q`Hs9W;b|z-tvh zj&04+p)TbyaeTX$ z3~!WVSrElcnP>@31p$tk!iaChv@CC^IX+j``Ei0`K9Z@15rm-=C?&zMhtPy9=K$gj zQ%svu2`YJ^$Wg%wy@c;MmON%@hExE78LLz(0>?YZu`M%@99tSEzT>G0LjjH{n7l@1 zhpGr;3~f_W1ZsPhkcHZi#0gZz)Qu5BLPRJ)P#LAVCykdq7h4(8$cYri0w41QwnF06 zin$J?Jaiow%42}#ke;MC4%LxR#g=IWf*RsL0zznbq3IJ31tg%5gf{VgY|G=J<$Ktp z3MQWGXvsj-l_GCWh=yFU#VnPaPk}4|#V4-)^NX@Ey>0(j+n@O|m)e+X%sqEr=`B9?*_%i7^{;ooHWfYIf2%KO zN!n{WAHw}tdh2#{4qx~LUA$x-6~FkX)K~oQe!#vbtO|`0cKD&vop9OHHo}hc^G1HtOrEyIS_V z-DQCO#X|clzyEongE?s<%tCl|) zUR|&{$_G+|^`CESzg=_V&Ygkw)7SCkmZPoN$iBI=H=Kbh)s2yw<2}C}uKjTZe*Y|9 aUzu)uDf;)LZANr@^{K`Su^0N7=l=yrkL7Xz literal 0 HcmV?d00001 diff --git a/smileys/guy.gif b/smileys/guy.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d884c3c15595e129ccdde0154828fb319e5d671 GIT binary patch literal 1123 zcmb7@`8(SO0Eg4A+c1w#r`Pke&$C*OZFnBr9I2y39QD+#7rH&HLg|Lu9(1)m%&`(z z>nxqK8sbPCLFuCs2@yh$=1xQsIfz7poZn*n345RShtD7Ieu9Dn!B-Pbflh(sAkhB) zzFx0;Pg@}1aRVqM4m(AsEowH^YYJIy<IrcThQqK!68&zTXRZsLP=rv&bAgii3xZfty`s1t*nT8`$lMV z!CV(|x~`7A$i|FK=qC8kI|0V0U+;bvoVRA_X-tL1!#; z`4UF;GgjtLOgeXo%EOG}s8pIpqwVPIBh1oS9MSTMjFtPC|MPV&gGXlyC#M!B-eS#W zGhv2^8k}6B@_B+)u|y&IBWpRvdzsBgbPp(%8*Q(82}A~+Ary+_GPzP!Qz49U6Y-XL z{MAkbS|*cYvC{*?*m*LC%@Iph*H=Z-Z4{Ds4=UyhmsjLn$YHTq@@9N;5QF6lR^oW55fqnAU0+)@=y&$__YPwIzc_*pIQ#<0 zVh?o0;@sEHd3i^US)BpwENspPRypVUef-&J=R^wn!dDQR^Io|i zTR*(TiAy0boh?BDRwo_q4rgeO23nu};Q^&LLGnq(Igc!jLL~XL>Pwd*>kCnMqV2`t z8pi}0-ZIoKyw$hF9%fbh?d|^fIlnLR>YVP4=a`OOE^GKMF=E*1zRbGOC6$Rzk;p>h z@-xK57f?jSzn(cZ#}_)1kGEX=YY+6?(YdM>QfPJ7qwwi(_5tuSu9-U)Q5S=sUx`E} zuAO)t(&+ZcgFi>V64B;gZhwpP{+pY>Mt8>&khMK`(7uq;OYqCBF~g~x@gj%%{vUgC zf_3d{%G2n0T(PY~(#Bn<#JP~>h>>4T4kax%L*Pj_xGt$%x9*c&*@+!wH*N;K++COl cjRuR$pkY^KFAKsv)_bSJJk{2ApMyOA1E${0z5oCK literal 0 HcmV?d00001 diff --git a/smileys/guy_hug.gif b/smileys/guy_hug.gif new file mode 100644 index 0000000000000000000000000000000000000000..07a191ef9524da1db1ec9ee7c808571c1ac3907c GIT binary patch literal 1142 zcmd6m|4-ax0LF`efqfGeMHdg<7pBRE$_62DW(2{N!0@t7!w_+fGb4_fi{9cnF<$i0 zf~TqGJS(eN#W!1>ovExb&1jYe3RL$>n%S5)^No4qN>)i@8oeLxhxZ5c_Fwq?{NzbK z&y%O8mu+hwsblJxKN%+4`nY4nd^?KFJ`W91obo+qXdvdL$Ecr3rxG;CVk<_&G&1@e zDegsR>+GbfDx}rUsIQLg@KHNLUvL7|FIG(=a9j!8CQ- zwuD?Jm*X85`>ty!e6d&@i^r(n+SSpT$#9~;`-To3>|p~7Sw#V&C~BHYY0);UL}E+= zGQwVnqcm)d#aMz7ax7I!5`qXnjvO9Hf~;r-H$Fbjc@VmaLW5D=uqB`wCNvFIl0@vf zp&eacUx%g*p+l^s@B5e#*Rg|u6y5#QXFbnLkEbYMMM=V3GQg;aqY_X}%TZM=2z;U{ z&_SZ4>bh#0mIqlI+OjMoM@=M>2q6~{>URhNP)ZhEr{NGGp2Wp?UI;AH(e+d!F3UQX zPRX)LJYNu{Tu!ho%ku(Jl%Z__AYqIp31m245_6e!DhLACB?u9WJsNfZ02DN1iAOg#>0gwxYf(%NN zX`s|I@kFVFZ|J%KZCg>afB#QvWJn%TcV2#N$KR_x7i+&}tG_(4{q*M>JBF{W-99;e z&#v|rYRq?b-d|SEHMP9(!E*Jc?t$;Tg~bQzXP$qqy-Q;!r|xaue}3-ekB_l0zLPnB zJ#S^FqNhKt=`J*!>mL60W<~O7pZjplfk)=>YGdt{0~Kdl;NdE^x%ac_UuU{c-S~db zn{BrqTHAZ`n>dI1@x<7sOUJJE_e7V#t^0PLxiNfU?MlxxwTE9C+*Xb!w&i<&PF?Su zU0VF2ZR)L+nWxwCU+vp7?=9^9aV3AS>5XgNQ+pr0)VZPY?Wup3`)7ZD{ln%&r0d8& frEzQTKwTtvDDufqTNiiERgAp%#OBHh=E?s6Ig8p+ literal 0 HcmV?d00001 diff --git a/smileys/hahaha.gif b/smileys/hahaha.gif new file mode 100644 index 0000000000000000000000000000000000000000..dd46af1b023359702d0b258f4ea09f1757791c78 GIT binary patch literal 1678 zcmZ{j|5wxX9>+htfXO!(j5Q}AcP#vpB@Ou^g4Y8xknhLnsIS;iJ++H9s@+g z6_ZGZE$%K1BPH08PcRX22M0|2NE3$+82SkoexgO683Bim6VqRSTr9ju!%NpmffZb$X!l5Hoh>!!>G8`SL zHobz@f<+Z)sbkX?_(SiFC=FtIr&Tgi#kx}gBgH~wt8_VOWEFNwK*=T>fsC zUM@s#9_?1=G}y`jIpp)7!pN&|RSwR9FvdpU?nRjZ8DOc~)2srtRJPO~ikNmrC!X#s zB|89*gh!P1)*+yb>VbR~at;s*vAIc%i2U&yShWK}1adj=yaR|Sw3G?2RRdKAc8$=g zIfM{BeRL~DsHd9>Y#Mkp$g?QJC=J+go?TaHsR&tAhB_(t1l*1n%;|tO62Lb5inh_ayI2 z*&ZqK^uRDI{E3%`ANCY`$z8jjgoj~12y6EZ?SG~@c$d#|{1=q0b+~%n?)mWY;v3DM z{f~8Wx^%v6=rz;Wd0bRoElgH$-#8n+<<9vN?Y6Jpi>tO>V#U5K`C8_2?@BYg%#Yr4 zF7HDAC#n~sh~Cqua@q!cR}PQgI<;B)-=zzZlwUPng43536n3hU-Lr76;kZ8eCH=cU znvdAo>(&R9;zKuXHuHB}eWN~Tasjx3oAZb*B}4r^Kd~kz(on3|tD@%)On*FMy!?lX zm1V2v{ioem6Ba5Hgak%p$FW24^}l#@XZFv|mv#BYX3w_2c>CTL38tGF{7qTP4U@-P zPJaFRx9?s~-!XCj@3|$$Mb4V;y=Q-q&euPyc;6oePWja@wV4%>o37M8kQpPg249Ed$8+)b5tBA#6pdo7tmNmhWo7KJG&spSEhaE2V7SyLNyxf8IhM%kEpBh{!!AxG oOSrP@i62OX=VHAE%STRd){dn3Rxb7sTQ_p&WKDS)+(0bxFNfwxod5s; literal 0 HcmV?d00001 diff --git a/smileys/handcuffs.gif b/smileys/handcuffs.gif new file mode 100644 index 0000000000000000000000000000000000000000..8262c129bcc9ecb76f391fcf22d889689aa21abc GIT binary patch literal 713 zcmZ?wbhEHb6k`x$IL5&6|NsAAzkWS=^5ovVdygMK{`vFgix)30UApxC{rh+C-hKP_ z?d;jJj~+dG`0(M=r%(U=`}gP1pKI5yy?y)k>eZ`v@7_Ip`0(k|r}ysNd*sNG^XJcB zym;}@p+jH4etq@o)tx(ce*F0H@#Dw)_wVo9x9|Az<2P>HxPANfty{OQU%&p~!Gq_| zpMU@U{qp6@$BrHQ`}gmL4I3_8xUgcyic_af9XxpOz<~p+SFgT#^X8W?U*5cV^X%EP zZQHi3T)A@Bu3g)=Z-4pn<<_lR=g*&i=FFMTpFf{CapLIFqdRx*eEs_M@87>aeE0zL z*N^~;|3saOQWHy3QxwWGOEMHfGEx=XJ$(ZhbQpjD6iE#1{~8#Ynp;}i+B-U17@3%v zSy;Qe+1Ob*IJvkv*?4&QxcJ)y1cih}M7hN{#U&&qrKDxrWCi8eW#ttVm6TOf)znpZ z+B7u9CN^nl%jz)b>ZypdG4p8aHt}oe8%Xo;h^sTViLh}ioZ~PwIwWjtqQun3BqL^O zW-e`^Cu(VB&1_TE5|y&<5Qn^G-J2T;PEK8dat$>GA}kz?{L*?e1THZ$HL%;p@$5`| z!N|_8>?H6};KXxCGz1GqaI!cV?D*)o NcFFz*QC21fYXDLnvTFbU literal 0 HcmV?d00001 diff --git a/smileys/heart.gif b/smileys/heart.gif new file mode 100644 index 0000000000000000000000000000000000000000..0f54aed795e529c39ab949a0d695e0c2287ea7f3 GIT binary patch literal 1219 zcmeHG;cprR6u;gmQlw-sN*!evI9JvZf@^CC?GjvR%Qj+~47H(+A=^1gMk-m^#Do}9 zusc^`NhOu7m*vvk>a~&uw~HZ@M09l0_F`CvOEZlzEh<)`{Xh(fe0X|(^ndX8;eB{{ z@BM!7_wr7iaajA$s}VKwD}qoM79|LlVRG3l&+}1-qf{z!em`foGl2jnm&5nl>2x|3 z3W3AH;dq9ob8>km94?p3S&qvGgZWsDmr8lUQ%I#Ml?o`8`E0gmu@q6Xkj(<7DUxJ` zqRJjmwOTEs=)Qntl24_IJ|6`9ln^sq)k}b-7Z|!ql2FL+qiA`1yJ9p_(J08J^?DuR zByef)d0}*P-{XNI4;nQX@QQ5!@;NpZqlLUw3h5LKSQ?GSzA%tVg3$oM07S!$T#hxH z8)IW2)UyngNHkCsCdMEc2f_nFV~m9DQe9ZHRs*#X#AriM!WY2rgKP#;Y+0zmG4M<< z7}f}d>WKu{ZE3Zdj>W*`qJ_z3BM7A75YSYkRDwht1dvg1Iv|;3Sr+1P5J)u|HW;kc zYP8G6;y8qYkjsL>0DeD=xj-N-6#>IQtp>Xt3I&*$06`T+fnWvCLoNrxQ3TUcDad3X znEX%Ct{Y32-x!wn+%R7qKYV-r`U^d(!RTM%(qW&>TcbO?*leq7@#j~+ zPdK5%m5u`0F|@a#-53FpYiaCT3eZZnp1=El)2=aK-WC zk6Yi`o7!j#&Fr1K*3mU}O@qFCbgOmf>DDHuFWf(cN4w^k7`nK#E|yQD#L+MRI8TyR z=aY45=Oo^8?7h1^jwX?6_9sod^{WjzCR&OtjL3H$K8Kv1I&j_P(@i&BU>Ch7krV#_ Dy;0qj literal 0 HcmV?d00001 diff --git a/smileys/island_palm.gif b/smileys/island_palm.gif new file mode 100644 index 0000000000000000000000000000000000000000..d26fbc1c2af769d12ec8a7d0c6128a53d1f32d20 GIT binary patch literal 1203 zcmb`G|8LY}0LHs9g&{2G!3HyPvhi&W1j7bSl!Y(z*e+wi3YSU92{*aKi=3At7sTYU zb<)jK8`gy4s-C0bF&b^K(FU9N2H)wcdoc|ZXtbIpG+2{r8n~E?smba5AN>6OJfB~l zXLnzu>&e3nL<8{~K`dk!^2ul#qy;T2=mO9Iuz_V;?fe?UGkn*|vJtJoXcFHpwcEb! z`+ii~T4dw2PKz328k$7M{gNMtaRqX$oI1d6l1(`w4*(3xCC}1TB}uAWmIE9HN)$x1 z8dVO;17bG~=`bHg2&$=A5R`38hc1LgK2apGg)x`IP~Tz0+CIlba%1a#L9p)pjv7QC25V8s2FmQsft=YspXQSLRKn)ANV?gy081L zZ5lWM5;Bv8LXI;z$8m~!(KTR9i=jf!01}5dg^D8^h1t4digaDq@-54R0u;6?Tj%nU zCF!o7!#T|7awuo`h6SahmSiwvnx^M@hGp1Tv4B*dVriHzm&>S-H=(M~si+!_$uSnQ zzyWs2W(>x6Ot0+C30%uCF@Odvl}nW%P%MQrIL+1)D3Jx(f?2>0ZWUWenM~qj4&+Ec z>Yk1T8jFms>xN+z^n%J$VIf@14)~s}X5+{~7E$%7$Acnuq?~A=SB$(AP430KmRN1i8=oJ0SAg(PYS~?%{Cq#$+yi6?!9sL*`xc8&vahAIeKc*nb1D*{F&*N zy1gGqcM!|^M}){1`L6yxdWg9+O$^t(wfL3U@w&hNTzhTVYGM82@Z)XzlH%Z^Tg0mU zv!mPDR}ZzfPUSC#AKWr^P5IP#RQxcU$=tk9!#w;(xcAMD?KE>_^NU~2&Z|23+0voV z^yw|`>D5EaPaLW3xN!dm)y<(V`#xWNs-floIMl;Sgmmhll z;K(#74R3s5ojHDvYdd)P`lhjMcMtzw|Iu^({Uf~_C-%-T)vt};`0<(Q5pj0qo(0NS z)%=&KnMKEk?_J#(y0bgfICbUTXw!xjTx3bh`1QW@)af2Hf6p(~wY9MmBV+YiXM`Mm z;_}XS?t8lC%J3t<{?Qw1d;ikyo|UZ`^87@{xrwVyliO!QjVowF+(FhZ4G~ZM3qMrE A5C8xG literal 0 HcmV?d00001 diff --git a/smileys/kiss.gif b/smileys/kiss.gif new file mode 100644 index 0000000000000000000000000000000000000000..8413fd935c64b2e27bf9328fc49d416dbf1b87fe GIT binary patch literal 1123 zcmb`Gi8tE^0LP;>Li{4)XxCCl-@GJ?G*RcUu_W$et}V#s2r3qeK7IAN^-Vq6j*e$u z*LB)O8;^%p;)vrp5*dQXLFOi|5XT%568G$X*ynxU_kI6>&)3J#+r>5B3}gmc1%b}b z&reQH)N1wN;o<4&>Cw^A@$vE5*_mo@Z-UPku~_^{#xR>bR9h=&d9F2?W%1ZBJyjz#cw>LL?-jsL8#VjU9@86|p?tiZ-d2;x! zT*-L7^|pNH?H_9TOHI*Zb!O5()bGaPqZ(lFcR}<707MKmkieiLFsSr~x#-%}KB&P5Ys+pr zolB?JTUidn3`gKb;~2a7gaoOjg#-!=LjgWuFbEikpun_`&xE7Hh>7utnTgN{_8y0o zayaaQ{4PiPzi(q_-Cg9AxOrDc85S*bz{+DtGMwF_FF|IHk-0g^+?;2f>?fV`nxtF?{OOwl@g{%KNXwU`!eE|eM18ITHeVKG_ z9@rQ~<}qpfd>CUZ)>csfuE{i~`SEdto+ zrf(TGbW!_f6V%tt6eCY7tt+?U{wl%cc>~v-GnU0Tif-|Z&mV!bU<5wQhFE0oRZ19u z+Xj`p=fa7DCaB0dGPjgCWQHNPKRCQ(Tl5k~=9gJF_6k0Bpi1lFNBf4ayJRj4D#H7P z7VbH!&4tl^k)>y@HeeIMFR8#kg(K}dpN8J_DYhbJSySPa{x2}`gABb<+u+yOoFi>i zS#>A_T4tZEABl>rB{gU5*O=Ck8j>Y7NgHEYxvg1#Yg4_oztzWb9)D!)R7Ap2`fW_m zKcRnbND{nqeW+vis);I%z;nEGN%sJ!$&^OGdG^5`;6k(`c)BbWEqQ5O{*19uV2&|? Hf!zKDp0;3I literal 0 HcmV?d00001 diff --git a/smileys/lightbulb.gif b/smileys/lightbulb.gif new file mode 100644 index 0000000000000000000000000000000000000000..33f6d0a0e4c89ae197b1023f94b61eb3628b0771 GIT binary patch literal 1062 zcmeHG?N8Ei9Q>d&$-s~mY10Oq(f`oPZujc8yBBx6nAoHH_H$`Kg9QMD z(DG-wz5$y!M;XlmB^O387|o?<>M+}s+-bKM9%GX^uy}3bN_RRME3tRP83ZuQh1my~ z!*0=3v%VI9vo8_Z$C2Zkvo}$d3*!|mQ@6zVJ_)TT9P*gaY%si*e7;P#-2!B)MYboV z8!(thSDgaXO-IIZ)CTetK%JiGM<(ikx5@BJ252l0=?<*EfHxe_J;LT)-T^l>K}9ou z=mTh~L47shmr*;E0roCHN|xaV%T(ZTx8wpe0b1!7R>Kq{6BOkPTMmpoAeghoMrIww14K zbu|VvQWyE(J0wGeput_qFeimsm)HXR7eFhMvb1)~27HHS|akB{*{WBZU!D z6UbiA8l>(hbN4*27lwdGd}DOlr+rm-f;l92JZrvce)#wc-c3@O;NI@^NU>SJea}J& z)`zF;K10eb=MCL|aL_?|I1OWXnxf@;-QIk?ZXG?_yPkQ;tn>4xOBxQAt}WXX&W-fN eG54@7;gt!DC^3Z;7XLKIr}^lOZ8kCyBK`n+ytecJ literal 0 HcmV?d00001 diff --git a/smileys/lightning.gif b/smileys/lightning.gif new file mode 100644 index 0000000000000000000000000000000000000000..2bb5a8ed6c06985b31a4f9dc3ee160135fe29fb5 GIT binary patch literal 5991 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 PI&pk3ky>Pw^Gp8$is|~O literal 0 HcmV?d00001 diff --git a/smileys/martini.gif b/smileys/martini.gif new file mode 100644 index 0000000000000000000000000000000000000000..afd769dd911ea9f61be12472a980dbff8f75f8b8 GIT binary patch literal 1078 zcmeH`*;5mD0LNDX7@1a6m_eo3Rz<6wdQ`Nd?Q~=mH6Cr9KKalSJZF6H!KY4VItIMP zW5DU4?a&s40RjedY{(&Gf1BMT3(01e&9zB(6BeQ&lEIi`AR&b~Jd2oexm+SS7kQox@(C|H>t<)Y z{@Eb^Din@SclAAo)uRNFeEm9;$qJM403WAaF$?ix7>yW_$TKiy#ss@L;2ULme*^(G zf*8$avpg@L*f>c?EQFvR<_#m0TBBez3Fxx`1z49W$_8VhaMb5x=jZ3s=`@a8QJf*^ z*cdqjEH6|>zy5E+EFZ`5sWCDFFv@PX0~8-Y7@U|^BV3yr^vH3;P!M3k2tolAOD2;T zM!-5sW#ZfQ_D&TA8-j*m8pFp@sT69qX>^nU2@mT1u-;+Dtf^EwpU)$x1HnQ%qX)+w z`TQb19?%cFlp50G4HXJYg+iWYI3>)ewdArwk5`ZnGVqYo>kE5)Lhk^h(o#M)+|$p< z6*S9+=jP^uTy#+5S189_?m#FMvO6bLT0v{%G+O+rQtNb59LJF)X#y4t!NdBA?tZ>c z5!UDg6B<%H9r^RG_L-TPg@px%aj8_AfhRio6I*wmqo?1YP&!e}uhSzIizS!KW-^&X zBH?y>05BuKjG|aD$Yrzh%dP+CEd!rI%e?slBwm76h^wW_4zx)u60fU+IzdtKJJLVa zO+d2Zvg)ccpyOK8O35baqqXKCfN!z^$Ty^M%WP3wI{GjGUoBPVPmg5y4f7?;ty61XX zg<3Rl#vt2rr)|gglJaTh%10Huege(%L!Z|{vIc9*_QujdPqgrJw*5WU zO1{7U{=3%J+MD;$+M64!^2Vt1(m<(bVzleRntwm}Vd9^Spqr{Z_&ZcmzW0_S&Ymh; z|3&k**2hQgRvq}YrUmMj6({N+?7jWnmXi;6SD$0xRr`9UL?^E%)3J)a(~lqBE&6!_ Mlc86Oil8t51E7Z$mH+?% literal 0 HcmV?d00001 diff --git a/smileys/messenger.gif b/smileys/messenger.gif new file mode 100644 index 0000000000000000000000000000000000000000..ddb69ad63daa6e3b69658f09ae36d40ac53dd196 GIT binary patch literal 1248 zcmV<61RwiHNk%w1VHN-u0OtSz{{H^>`1s=D;?>pF_xJbv`}@z&&!wfMrlzK-sHmx_ zsjaQ8tgNig&d%-a?bz7Zyu7@(x3{9AqNk^)?Ck9D@bHa|jrsZc_V)J1#>SkSoWH-n z*4Ea_%F3IYn~si-?(XjV{QQuRkXBY!IrlzP$N>7G|h}G8C@9*!vzP?{yUnV9dhK7a<3kxhPEZp4M$;qOwt!l`@ zgYM$T+1c2~$H$VAk~cRuadC0=_4VfF=0`_I0s;aE2naqtKC-g1&CSW_>018w2maLu z^u=M%&dq>;fGaC24Gj(5-QCR0%p@cv0|NshA|koDx$^Sz`1jiW>p%I=I_=@j-{9e} zu&^*NFa!hy8X6kI!^7L#+dx1-2L}fQ1qB=&9JaQ${r&y-^4{p;%i`kXDk>^PMMd7; z-c(dn6ciK@5fOobf$Z+`;o{@h*VntdyLowe5D*Xs1_lxm64}|=eSLj4Ha0OaF&i5j zG&D5C#Kf_&v7@7-IXO8yJ3CWTQ<<5WZ*Onq<>jHFp=D)dy}i9_YirHT&7h#5n3$N; z)6U$wY9bU`Sb7T-_60U*U7QVzp1*gpQfXqpP-dW!oRHZ^Yh5WqsPH$(aBBG$4kY!V7#}L z;^N=*^z`K9gnnK|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0 z|NsC0|NsC0EC2ui02Tli000R7009UbC@_G40RsdOAjptm0RsmRBv7z`L4yJf89F$y z;DG@M5kg9sKp~^R3Kke#0DvKbh7BA#c=!M!V+au=NB}5d;slBmAu6a?!Jh-oI#UD%^HDh+PHbc!GHodX|TkR1HjB2 zI(6#U!BFrHo;(f8=-I=kkDobz00j~>h|nJZYyvnS0lN?iLx&LgNu+2Ii2*1QF*16A zMk5mq3h6PFz|kWykSNAf5SSto0|3H_ODcmRjDks&0OcgehC!tg6-fM%qM1ufZ2;fmBC}@(vCYF4_Nhc3vRD~y>fD(!*qaZK|DW#Zl3My9Pwiz4-DAFu@2j3^BzRa||-cD6>q70x{E!GtWR1jWp9x zQ;jv(V3UnD+i=rO2m=-1%{SnLBhEPFR1iWr=A460I_j*$PDAay;LbZBfGJQ2Tfp-I K4MqtR5CA*M^q|xL literal 0 HcmV?d00001 diff --git a/smileys/mobile_phone.gif b/smileys/mobile_phone.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5825c63f4404c8b0185f05b908f958814ef69f3 GIT binary patch literal 632 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 literal 0 HcmV?d00001 diff --git a/smileys/note.gif b/smileys/note.gif new file mode 100644 index 0000000000000000000000000000000000000000..c449c423c77f99aaf4b438f7d47946233e37ef1d GIT binary patch literal 1098 zcmd6m>ra|@07l==v~kw8RU1>C$(ogAZEd$+w#0T>qU-9VYqPdnT;{aXl)4HtDk=p; zR8SOQh#OuuSEHg4t5qR*m"ywqD1ifo;tFCZd{P{0>{bN|K8=jYSOb7JD6Bd(z@^+ha63UM+9W&RB)*>%7_(E?rGTzwD}?cQ_nguNOAGk&l}?1RK?L8|;f<75&Xa}?kK%@ggfwLlga6=DUtgb?){oY2Yb$HPLV4k{bgCv(4Sm!Tl0vhOE%P_7?n)U z%`C30=+@TO3 z#JEwrw51yS3x_vSeiZHQ?RWHVRPprBdyHbKWnjSA!PBvEved+7N|LZyxXyZNnw~?{ zTA zkjVg8I>3}IFL>eFzc`kk8z&Wu!vf_{mwZe* zxwW-*aJK&&7oY?FYXS20LWg|AVoyXuhkSfbUdn``-a35L?-+VkBK7eNK;3S*E0rDg z4?$tnl15tT@zY$z18WimxauqetPgy&{4!eF^qL%VX zE8dHw#-6-V92;;ZhJ(5%ERGBM@au*zE6+ait2!UwnLN?-=xEJH4_*}BJAIi|dl{{& zy+(_U3jGv|3Pdj`r{9ghzVG)SEM_L`I`fPV{~>$~Jwe^k&t->XOFt*ObJ%A1cta%h zNWgjYW6|pyWr61s6#PnF3@7m`7Ah^UuGijLQa+iGnPIt159uS^tJ|*PXKj2MW Rnfl~L=~d`f@CoR%e*yki)Lj4o literal 0 HcmV?d00001 diff --git a/smileys/omg.gif b/smileys/omg.gif new file mode 100644 index 0000000000000000000000000000000000000000..32252cf96888fe457ce31d15858e905c8ed8aa0f GIT binary patch literal 1197 zcmciBjZ@Qg0LSraP(bRS`$cro3Be!=k$eUR4;)@5+KEYVE$KT%o^{PnHoh=RiLSK&7rWchoY}|f`8$!sTsx;N7(T->h!U&= znbKJF3h3Ek*-Y6AVmLiq`i?3WM)3hdO+Z^D%xanH0LcAtGMO=}idSSoaf~xRE*Pob zX}EWiXcLHdtvD9SV!kqs(&d9p#Otp6OAljA_}O6PCrz;!C=VhnZ<2ZpWuYsMGGB8f zqY+PK>vh*xTU4P^sD{>6dCYdOi5SX4{Ikc_aMMM96-`?q;bXdiMO3zPVq0Am z_r-I={H$T%3`H1Nx?$?}wh#x8J%8wE36ASygOh4xrVkqV;0oC4#G zi9>Y)eFwVY!JOcmL?Aj$i!s_PkeBeM+RzXN(~wM=Mfaw{ItrqPu?L!Zfl)1!6v8?J z(SF?dnSTCQJx~NPgS$DD<*C7-mbIsIEKk7Xqj?AC*(0@R2l`LJYJzbPxAM>~fbudd zCJ-yEMlc1a--3zTwYQ=<(li+Ezru#8dk`f;E}&Z@(Vc>!%h2D$!%OH&geZ<`41W#s z|I8Dwdi?^}FR_5_;!L-JWnO6YWrV!3 z++*tz*awT)InEo4eUi>yl$LlzRBpHDhS)lJWiC!J1@8-Y=Eg`kcj$%3-wrSDzmf4? zyuu|g6`J0%?1EZ;I&4|>)rIf!7CCSaod4ll_t0X`B=PyX_8)|m@lN<=<*Hk^RqvY1 zdq3|_uU$8iO%a-jpk zUdi_qO58YJZi?tUuLcc^{-|lvS9`SH$mDr1JZ@a-)6Vv@<90b8l;o~3d$I>br+`_B3<&7qd@cn+%b>$9nTJ}Wn!W3vcr{{zgg BoS^^! literal 0 HcmV?d00001 diff --git a/smileys/party.gif b/smileys/party.gif new file mode 100644 index 0000000000000000000000000000000000000000..6c4f083735ec43e462d92c2c9abc6b9eecb36981 GIT binary patch literal 1990 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 S>G2i++!~xJ&7L(gvhhF8o7Eox literal 0 HcmV?d00001 diff --git a/smileys/pizza.gif b/smileys/pizza.gif new file mode 100644 index 0000000000000000000000000000000000000000..46a490c44ff1f164adddab9942e75a769aaf2a18 GIT binary patch literal 1162 zcmb7@|BDo50LIsEc;Cvi)5|Y+r{;MHo^_olr_y1Ut>-4&b?RkHEw$MymoB={LK`gJ zsbeg;#i*NZI2=O_Hp*l}jQS=^j`^Zf4R>!c==;M~=4fNLfC-nITo`=uF zvt?_vZ~dFCk=DrlNQA~4s(J$3If7J|YK#I^c!D#a6?-A5P%-X;l<#3s?nN-|(qe$+ zz^9>|F{Bi;i%3u5bVm>{WJ6j>XmY=67Fn*~K{*Wl5RDsB5*i6gi33KVHtaYyQevK~ zI9Ab-M?EuHm7_khktvx*nPGw26-J;_%@cjtcXcR7IS;F9R<9(fDIt*Mt`WerkBUBX zI4*ivv6NwEW}W0?gpiP`M9kV+hGCI9<5bVsPzPc!QBsx~XGp>@Z=W(YP+BrsmWhw}a`%cBDRcaNgr42;RQ&T`% zBJi1|#4s`m6ig+?+zN&n7wa75eWEgR)PqG^OLD4FW5jc$5Q`Y&z{>D2KzfEziGYG* z7PzakYJxk0>$=Q^VZeZ#c92C;8CzK!YSa=q=f3YlIUbPO?j{5>#lWqm^wI`US;t_> zXL@L*p_;HQ04gy@8^*ODs_@Xq)dD5hbEOaoK+Rin)DWY@NaC76EO9&Q5hJuRUM)Hd zHK7YgX^sjQq%Cd4H!ZvaH>*Dp&SdT z&RofJRi7cEk06laxWtKKhy&ay`HsZH&~vSS|0ms%8V|n^spFCD^=*R}C$1f?YkBlR zt9s~4o!oPGsBaQ>EN%Yq@ArQBZBFBwj`E7D6Y$4UyV!Z<)%wrA{U+1$NagpnjSDU= z**iJ-@+ac_-c=n{I?p)gb%>5(s&iK|7kI$KYSlY<_%xB3tSE>kQoAwrcg|+wV6X+q3c7w8_2qw#>b-?ZnpZzRLp*E7cEn z4=wrb&rL%6k)}0cjhC9I35RF5AB5}g-k#bv{lVDO#K1c}EjJc9CpXPp`SyX+LrtlV S>G2i++!~xJ&7L(gvhhF8o7Eox literal 0 HcmV?d00001 diff --git a/smileys/plate.gif b/smileys/plate.gif new file mode 100644 index 0000000000000000000000000000000000000000..3b3851733a73915339cab6c9eb1ac06414635956 GIT binary patch literal 1068 zcmd^;`%e=G0LQPuW>FFmm>T0E&ewcoqA`TMlDes&CWg)ZupgEU{lP?%CELO;F8iTc z7%WRR=P#>H0j0XWIqrIG58A`hqlKP#J?^fhS6aBkKCX|@@(6T1*Zm#)B;Oyu$tU^d z+j#j>!}~XO1G|AF0Bmh-ZEkLEY;3Hqt}ZSv&dtqbG8svd;_*bRm_#BeNvTvSpUtn#K@_9YGhA?z3kCzhNrnp$q~GPnAqX}aj275}<2cK(>2!K|d07-^L*Z~ZIz26l zu|zVSlwQXZGlCf6!#;v^Ixu(u22G&ZVAkvOdaWMp2WgsKT3VW)pXVcysc4i5a2~JM zWEv)Gva6 zWB?k#FpQ)~mg5+PeTlt9AOwM}Rv58Bu*qQT>F(BQwaf&=^F`4qQ@@#Jn9N*Gd>s?S z+3_*Lg}FR#&$!1&`be6jS(*#7lfE%R)AwBWw~io)l$2swc9Q2|izQt&$mN54I1u7r z5fnax`@F>>#rW9}7n%x1W~Kyjde&yK>2(Is42q(-zP`?}9EJ^3ls}e8gdeF&f$JjKWazg@%X~R0?+fKqoX#f4Mhhb5VAlPyA?&P zC;}rUgL%X?va+%w3L-^OxEpsk9Cka3+EAy%DF{L~lPweq#r6N^oC1pc_XR+{3CQI8 zo4{U|N?v{9t1UW#8En>;f75nPH zlLSQzu=9YTz4FYx3+2_vnl;S>_b%?(bGikW*Oq!JcAaYt+3z0e{O#?Jek>HklBUXo zpLW%p`JwD`)sd^}bKftNU8y;KUHgUZ<{Mr2Pksq0X{ckzFYkSgDa#Mts(5(z7S((E zk4xmf`fnqSyVZ@<{<^kw2vr^Xz5C;zRtx`>jwx!-tK@H;ZIgfY&c$E%^0#BsE=|*e z);HA`bPt|i?X0`u!yDP7*PhhgnWYsPg{-Gbx&26MjqdXo_3a;Y_*BYvSy@%X-uov4 Tz_x=2^xya~=URtM27LH0);|LP literal 0 HcmV?d00001 diff --git a/smileys/present.gif b/smileys/present.gif new file mode 100644 index 0000000000000000000000000000000000000000..8d48a4e8a235c9c064e37a7aa41ef62fc417c6ec GIT binary patch literal 1252 zcmWlYe{2(F9LB3FWg31=n1f9iY!U{D1LhcG!$~@*+ZZ#vl-Os&p%I|e4gjc zMqBmjjsjDG=}(i1YF#KtTOeJbP$UvanW2%CG&rX!2o&K^qIN^&SfT|K57slFlGxz5 zh)2Yj?2j=g#MK?OeP%UTy>Pou1Ogt;1Lp0#Cd>e0dz@M z6fJHC)z2prDA@{9H#S%hU4Td-odWcYmI(_X0!axb__06+q~xF;ng_C9tx1D09(UG!dyHik#4@T9Qd8UZPk3U)T9H@IiyK4#{ptl zPb(5bjI$2O9+4VFiF(%6g7pLl-Jl&uVjMs)3VgSEyNa*Y2vZeEj9__)i=72E3{p5ll4AO6 zG3GNeUO-`x2{{qKS^)5Mz!We|Mxsd%E@Xp;K{<%^7@!1*djMmU?WKfhuN#R`%DzMq z1rQy8Beb(hPWg1!ig+K2TO}&Z5_X;S8hkd6kg}v0yBP8)$xe}?uoPw7okA)Faulc< zBqyXq2=qAUgEZk#>982}D;b8(qE9BZU^yR;vra4Hbpcg{#YlEcOHEn*{{>SnnD*t) z8M$j-+&!mz()h`vL-lWBV*d;s=HXSd8*~b+WPjZ)%(j^F8bK3jk(u) zH`sc1@k?LpP&Urpdp~SmblW}~jRbjlUe zn!fU`Blj+a20G4IKk@xG#;%&6|H*rDjV%lxF1A1HDF_vu{Y9vG_2tXsXGb=^G0Ii% z%DFLK-F0m9_Ah=On_1FSJO4;&e6jdw3*=tded_zBhcoqSWxp@Hy)MwZ%rFnXJL`wF zAHB7s`3^aKY5Zwmec_#7O9yJUF7JBA-2Qac&0ON%`CBF5t{ZQBsmOABcv9$4UVQC) z-Ff{*`7mQcA+siL`ZCMoKfZf*MQPRNN*eXd!oMgg~!$G`l7PDlN;u> z%)UFY%GumKeR=PK9@Ck literal 0 HcmV?d00001 diff --git a/smileys/rainbow.gif b/smileys/rainbow.gif new file mode 100644 index 0000000000000000000000000000000000000000..dd800b93a9ea286eab0afff68613fa4ef8c8a0cd GIT binary patch literal 1102 zcmd6mYfn=L06<&lv>_St8jFcbFkrGN>d1(3nI@(#Y~Yd^%+we+0huzg3Ra_$b%VkL z!ppHx*r0`$Qb!*!P%A_Xw56A}qmSF$cPZtzm$q1JOMCl-0%QMT=MS7O=X_CIbo$fs zY)m%Bjlt~h?rv{y$K&xxBod8AH#axYU;wd!kenm=`@sUYTE?rAPTV&xj<{eD4R~X* z*s=xGh}uk(m5$+B|L_wZgXw2K-5964CR^Z{pR9^Lw*!jDV>>%LArw{1Ce4D|Zbtjc zlYex>cBurF>7#%lIwuLqx)5EZ((y~Dg;Q#f(nIJ*Fc?tGbC$=62zl%!#ZCso6~4qR zU+9kAT?M;J-=am{?e9eq_I-!>yJzO!Z#2U8V8EM5B($nI^Ye!=iTFGB%#{jr6uWa$PhT9iT-7>K=t)np-?3d80+hY zm#l;87);gJ=6^<3KqDkZX6btVn*slpfy+~}SZE*+^!wFxx|YxH^(VBW9@pzWGc+R? zbG>u(QcXmRIQ2tAdj?pqHxCTVI9-4;;(sktiRg;iK@>30uWeaOCIyQX4u_RAn$~EV zbtO=tNh|8ribsRsnhK4>3WZ7}QoeX$Q7XmgR#4`$EU+z$(?RRTQaElEiEJj5Rj;>5 zBHQ0uj;1<=B@O#?#?Cnyj&VR+SM)6dST-0KLqx(o^(%NBz|x2Q2J>2%>xXv62z z$mMbkq)}_N5V#lK|ABnW9{;_7!S7(O_(NY#FhouG%%j&^KW=Ei;!<#B_?!kxGCt$O zt3n2)X@6!qp*5#G>2XT-i82|ZJh>%x-&ryyogl$y9QlfNuA2a)WFNntMaJefcN{FN zHceA^F}uC* zWSO}2;Q6N=e}00^VHC4&y*qH~jt!5`z$MX6lUyL@raKjT=27UaT`T<>+myD0Ny)29 zV-lKE50{KorRVgem)q{Y?x&Hn{nYg(i@3O*FP$};@e$&vwe104J XJhyW{u7Bzx1y?!(HzvJE&mYTHZi>MVWbpNvw{U25O&@HmP&{90|Pk07J)gCS9@u)>NEx=iTc~V)e$hNWvWC_O9=HH9ahCE)1dr=X?by^yDU=QoK2cI zk}Q@)qgB9dO=anLpqH_v-A=MiRKG!2xf=)o8&LuVT5VpzsI zF4V)J+F;7}rL6gHWlMFXb3Uq8R>atrY{ZLOp7a0%S5Os(r%^DLj3tdfUGSjH8Kh)s z@^O0|suG;3!Ii`qC_*I%(#;sUYe&zgQTBM^xmc7_%nCP>F-U?|KK|Zhr>}AwxP^*P zG;%R?&x%xbR6L6KwshL|Z7rjd5A6j|13p&a<0B`MgA^DjL3tUbQ^RT zB!oqRwhYJ*Lz6d|ia~sk6r{ql9MnX!lqsMtyevh13Pigxa4mpxKxa`G3q=;!AO`6m z%RueHnN&TG1fXnC75b}jZ!HX+veqgv-~Yc^;gi zbxz)acCPb|*(MtTc7#mu-rC5lXIr0{7*g1N|EPPc(#<~wT}=h)nL_Si*jbeo^QQ)l zboNfXx@*Jqm4dkmlB-XgX00s<%JND3)n(3a#o;yC%j|P%H{4G$4E5UQdfAA1Q^Ovu z`qpQ=oTthUmQGx_E1+_(^{lh`en}izR&C^(NsChldzu3GkG=HEq0bmC{!Tt+>2ZdO zPZA@vusdzs>_~A@)|KV_$$qD&$BditbI#n2BJrfKnXB`B%aVsocHthOS61ZsB)=BS z4!@zj&bj;jh?^1b4VC+B=KNW_zO-HueCU>(lVRo3mMA%PuS>M-hl)Oty=SFKRN(m# z)@(14LttZiobwjmtjDb5joudzy$5Q63b?o8P?3-O<~J6Lw~S^_h6b zg{mD}da_phUb}ixC;K1KqOKF}PX*y?{KojT%(qiG^ycmv5%}6Z%4+Fu9+W-In literal 0 HcmV?d00001 diff --git a/smileys/regular_smile.gif b/smileys/regular_smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..70698acde10e7e3001a28b783dce014086ab6893 GIT binary patch literal 1223 zcma)*jbF=o0LMR;ht_p0inwU5T)B$U7)#u84$)Y z^(8i>FKnb@@lbhyQMyu7;WD8N6eUj;9>hqQA9;w;>-c9gp0T07H-mKhj8-vKmuyK3 zbFdIk5+Kf8Kt%RLfYBm62!l8ZWB2Jq^|_&To-`GD;b%l?PbB6<1oc(aBu&@XxQ-U1 zDin<@jFrLF7;sQng9wzYWrk zjtk)LVYVCw>B6{jBY!_0$KypQgmI9aXXykW10VEfbe4oa_#TzJQGXJ{0u0qa#6j2H zStHdb4~DK&(w0F<55v?4G79o)v9fsk-@9;c2TCHrivT|v{A0Kij@nGecl}FDy%5Bs z?k8$|NUh8RF@U^Yq>=2b%l0nbin7?5q8zUwkry${lyUGNg7IchEr@{P0!%s(6UaLz zF^0XP(=D6?e>Y9{pZsi!1 zAHuJhl11}~X(~zepEkoe^f;_m3Cy!>*Kyqs6xIm&t8~toW(DHgmpTVGL r$90}XrPF;!Dy|p$YO6iZczC9L#jpw$G-oczs_V^OY_ZCk0pI@sHB5gE literal 0 HcmV?d00001 diff --git a/smileys/regular_smiley.gif b/smileys/regular_smiley.gif new file mode 100644 index 0000000000000000000000000000000000000000..49364b584fa3b6ac1021fd7e74b0a62b105dd472 GIT binary patch literal 1164 zcmcJO|4$or9LBphTfq}fSIo&^snC%Ia3hEWHU^4}ZJ|-(Dr1hAg)d8kWa$r`k_98d zstq>dq$qVM3n9n|c1bg8?2<|@U6pgI%VqmS4|9nZJ>!|&50~XkK0lo1t@V%a`TfcB zyq@Ga-GA!nvC&FLrQ;8WBQ*?U5s(%PF=eE{%7+XQEYUAaIT689L__M87yXtBhA>8W zzfD5oG=o$!3!O*_RYfD+ti{_4;da!5N)k*7EUlFiKM8^!t)^0|l>*z?uq_j9U5b09 z83rv^CIB|^Dl1?SKqHM>ua$*-2+*cf_8W^{Q}CFDloDpuOp_dL7pE9B<65#g8vrd1 zNH{c{SO7}El2T};vq7-cVI|sRtAP5np7fZ44;9b^w-n+Ko%stubthG#@`guSbL(p! z5^>4Vc1vQVX+{jY5z*EnR`L`jy(ST8zKH1}i`7)GE<{0%`%xRyGhi!CRB`D^5QB_O zT!=0;+N>5Usm+)Lv{tZ4B!MYTA{D8?S;8cTnfGhO zp^Pl5W46Yd$pOS_CBZ0D9L)#KbgNA|mBk?=>7>F1nFnQ>wbDTNAvHdPvJ;K4mKZ`k zfM&vy(wKE3amqpGKmVH!JBs@63yv~$d|7rsU0B`<{5m&Zcs}xA?!A)H!JfhSrPkB@ z^~UjUE?$MI{qNthTjqBfT@C#QpUvsciiPt{gR!mtxeu0M;NioMjC{quy|>?;tzF+- z7`@#0)KdLkUu@z~*^X5Y{MjR~9es04sTg37f19oP`ol{fXS&~EXMJHhSJH6cg&(if zPCOZ7FSf^S*m)+IRCcpGCen zTXQm)+io~61#LQ$Ltwt$(?{Z ot37S!Hb;6&4p%=aWy=?!vhUDacXE&4>Ve0+Pi%LL_c)IK3*g0=4gdfE literal 0 HcmV?d00001 diff --git a/smileys/roll.gif b/smileys/roll.gif new file mode 100644 index 0000000000000000000000000000000000000000..b5341e0c2ee91c1b901f2aae45587203e54ba6cf GIT binary patch literal 3036 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 Lv*Y;{6d0@ltW2}p literal 0 HcmV?d00001 diff --git a/smileys/ruler.gif b/smileys/ruler.gif new file mode 100644 index 0000000000000000000000000000000000000000..f1cfc12dc0b72ef9ed171d706e965ddd6d17d3d0 GIT binary patch literal 132 zcmZ?wbhEHb+`_=daEO6nvFm?=Mqf(iyo^=ra=f_;bk3LL-mh5qzUKY^0}Bc~bfo%E+)g-|V>SQ6iW0B2 gQR{E4DbrT1*#BTdg^%9s^Dnkkoz2^Qnv=mA00PlPlmGw# literal 0 HcmV?d00001 diff --git a/smileys/sad_smile.gif b/smileys/sad_smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..4f3a9c2177e4ec55c3fbf0d68422fd2f914c7099 GIT binary patch literal 1199 zcmcK3jZ@Qg0LSrBoBv&Ncjsmm5vm!DAZ~o5+J1*4@W-mP#`LW zCU_>D@gxDFBRXNI2bZ~8~{{u^HJ-66aDwnwkQ8fXDR zh%p7bhac0;u!QsgXTb%!d8`V{?>>W^s1)?lr$DY$Dz%IscNg~=FXX$JIB69 zUlO`M$3Px6|Ch=r=Jp?B%9CL(b0x!<$()KTO%YAGvDROfh@KL%UF$*9 z&@V)Dln8eS<1kRf8AxYq3qZyb^*rAv`Oxv+d;aG(`V_`)?!@kKP!V8XSqnpY*YHRp?5E?xW15tyFxGL-X?#JV99A*UQNQCSX$H)iKVzha4V>G(5 zG1-QueK0D;1G$tm4VF<51DknXB3d;!iNf3NT&FfT(%OGalPsP9u$O>>Tia9%> z;zvPV42u!O0`&v5XTmZKSs@ztV!Vsn8N;O0G1dQqAO0~z-G<4>;2(!1i)xKTPb!o( zFg(Wa@8~!VegeBW>?PFyBX_*$bPg+%^RhQ4_PO|{K`kvkTgc^P!q%#>?&A7j8!7@@Yi+I8_!es(}!=o>y?c~^u~#H}h3mj*Q@ zn^x>~*oR9st}v-0*A6DqD- zqTOZ~KN9X}U zh^6gO_f`IjSWbfg3IU#nLC%NrCywS4e^{p&AJBA)sK#)pjzFITbKXkx?M-iQZ|XgT z=7V^;7pOBvP|>=Q^C5*V3;)uRWwM8KN&bl3}?Et7N}A&D2pb#14On_7J=3berqg8F9PX{ z9BT@&c7~3sBAb)Ye1_Fi8e(dakWzFdp<2i>-xnmL3640 z=RNvm9>l^{icr3rHS$_R??(FtScgEYAQOwoXwbx)5Yr1kGO~?~dJrqqItb-?lzxZ4 zT4{}dC69%v<$akjG=V;XhIr~xFrNL4uD@VxLdQ*19|0}oJoNui@Bd^u-t*xFF#d%N zWBwef61G!k%%{XuRb{f>Z0?U*txY1sVX z#_g8IW>E>#99%QaUXs);PkV0KXPUH6{@l53r;hF7 zckOCQKl{awT=SqVmUkoj@fZGMP21buBLiJ0kswKRy$yd)w}Ofsty^7q+S%pBVo7#F z`Jm)?>Yx0<>D>7-DfN!k+JtS%Ps5ArDQ9kzXtkoGPrwb`Wv=&V3%@>diyQaJw`;pB uef!R9;`cfGfYzQ`*CP&mF6qrYdd}5_y}rRdBFHzH^E%gy<6~okjsF2Hi-@fN literal 0 HcmV?d00001 diff --git a/smileys/secret.gif b/smileys/secret.gif new file mode 100644 index 0000000000000000000000000000000000000000..337a3e60af1943b279d2091df5440a1109dd8068 GIT binary patch literal 1223 zcmchW?N3u@96*1R+Ezr@VZl~Vi?IyowG$KqXcWD)47$Wkb{ z0x>W!b7V5WqPzq$%7~Io1;GMs!6MR2tJIag(DF99NP+gY_nH0^JD<FgphBQu;2T7QZBTYggC3BrmJG7NAYQEN9m-4z+N|9c33Fd!s1}&7nRiB=ja3NH-wf0ZMj3NXr*hujfUId=V~Wpw5dCw2c*5_JFszL{)CcA= zaH(6TYv^clEA?vYs+PZ``R1+q%DcxK=2c*<*+gm?Xavj^@K)DK=vAu@14XV)Rk4sU z(4%86>8~R{N%=|F!&Gtx2a(ESSLaUZa3q21_S+Z8Fj(o2(2X22bk?G2`z{b2H#IOl<*X zt`*@`Jj#(f`yhU%Q|Nwvk~E*4)v0FMcMe`-x%>Ej^Fh*-;%F6k#*=)yAWLJ|;zK}s zIx>Z!*F55B=;UuKAI_W6swkX6830WLc=Ul2RWy6s4rE;S&W5kybV3XMH$V)5z7z%u zHv245e$wkU@zip*x(M((7%G9sm!an>$Mr0knhhk~glCRp>lF;&ig;Gc8!X*6u8dik zj;EGc3u8UxG7b4Sq?<>1w;?~<{@_E9|0fu{=fexYq96cR{9GucF*fm!)u-0?|4iGm zC*NWTC@%kaS5`d`Vqk<~Io-0z{$m@%lfHLFkM=X!k!cF<;hh&0AyFslb8FJnWp&tB z-De3}dN6Nqen*>F*>W>HNopTe$umCMap){DhSw|KFp0*=(y3TxiT5hM(!N0PQTfkARW!WWSh1I zGB5cE-H;TmSps?^ zkCt+FOU9djQD(^b?TTF&$Mm7G+3l?P%SG9OIO5w5dT+d()t9yR`GLSM t_KjsJGq!K!WsdMGPUnpz7|+`jiHZnG;}M;uP$O`iNz<$s2C&(%|3BeS!y*6x literal 0 HcmV?d00001 diff --git a/smileys/settings.xml b/smileys/settings.xml new file mode 100644 index 0000000..029078d --- /dev/null +++ b/smileys/settings.xml @@ -0,0 +1,556 @@ + + + + + Tux Skin by Steels + Based on Everaldo's Crystal Icons. + Contact: + steels@steels.no-ip.com + ese_waly@hotmail.com (msn) + http://steels.no-ip.com + Version 1.0 + + + + #EFEFEF + #CCCCCC + + + + + + 22 + 22 + + + + Smiley + ":)" + ":-)" + regular_smile.gif + + + + Winking smiley + ";)" + ";-)" + wink_smile.gif + yes + + + + Open-mouthed smiley + ":D" + ":-D" + ":>" + ":->" + teeth_smile.gif + + + + Smiley with tongue out + ":P" + ":-P" + tongue_smile.gif + + + + Sad smiley + ":(" + ":-(" + ":<" + ":-<" + sad_smile.gif + + + + Disappointed smiley + ":|" + ":-|" + what_smile.gif + + + + Confused smiley + ":S" + ":-S" + confused.gif + + + Party smiley + "<:o)" + party.gif + yes + + + Surprised smiley + ":O" + ":-O" + omg.gif + + + + Crying smiley + ":'(" + cry.gif + 1 + + + + Angry smiley + ":@" + ":-@" + angry.gif + + + + Baring teeth smiley + "8o|" + baring_teeth.gif + + + + Embarrassed smiley + ":$" + ":-$" + red.gif + + + + Don't tell anyone smiley + ":-#" + dont_tell.gif + + + + Secret telling smiley + ":-*" + secret.gif + + + + I don't know smiley + ":^)" + dont_know.gif + yes + + + + Nerd smiley + "8-|" + nerd.gif + + + + Eye-rolling smiley + "8-)" + roll.gif + 1 + + + + Sleepy smiley + "|-)" + sleepy.gif + 1 + + + + Sick smiley + "+o(" + sick.gif + + + + Thinking smiley + "*-)" + thinking.gif + 1 + + + + Sarcastic smiley + "^o)" + sarcastic.gif + + + + Hot smiley + "(h)" + shades.gif + + + + + + Angel smiley + "(a)" + angel_smile.gif + + + + BSD Beasty (Devil smiley) + "(6)" + devil_smile.gif + + + + Red heart + "(l)" + heart.gif + + + + Broken heart + "(u)" + broken_heart.gif + + + + Red lips + "(k)" + kiss.gif + + + + Red rose + "(f)" + rose.gif + + + + Wilted rose + "(W)" + wilted_rose.gif + + + + Beer mug + "(b)" + beer_mug.gif + + + + Cocktail glass + "(D)" + martini.gif + + + + Coffee cup + "(C)" + coffee.gif + + + + Birthday cake + "(^)" + cake.gif + true + + + + Dinner plate + "(pl)" + plate.gif + + + + Pizza + "(pi)" + pizza.gif + + + + Bowl + "(||)" + bowl.gif + 1 + + + + Telephone receiver + "(t)" + phone.gif + + + + Mobile Phone + "(mp)" + mobile_phone.gif + + + + Mail + "(e)" + envelope.gif + + + + Computer + "(co)" + computer.gif + + + + Clock + "(o)" + clock.gif + + + + Camera + "(p)" + camera.gif + + + + Film Strip + "(~)" + film.gif + + + + Light bulb + "(i)" + lightbulb.gif + + + + Umbrella + "(um)" + umbrella.gif + + + + Money + "(mo)" + money.gif + + + + Gift with bow + "(g)" + present.gif + + + + Automobile + "(au)" + auto.gif + + + + Airplane + "(ap)" + airplane.gif + + + + Soccer Ball + "(so)" + soccer.gif + + + + Musical eighth note + "(8)" + note.gif + + + + Star + "(*)" + star.gif + + + + Half-moon + "(s)" + moon.gif + + + + Stormy + "(st)" + stormy.gif + + + + Lightning + "(li)" + lightning.gif + yes + + + + Island with palm tree + "(ip)" + island_palm.gif + + + + Dog + "(&)" + dog.gif + + + + Cat + "(@)" + cat.gif + + + + Snail + "(sn)" + snail.gif + + + + Black Sheep + "(bah)" + black_sheep.gif + + + + Vampire bat + ":-[" + ":[" + bat.gif + 1 + + + + Tux (MSN Messenger icon) + "(m)" + messenger.gif + + + + Dude hug + "({)" + guy_hug.gif + + + + Boy + "(Z)" + guy.gif + + + + Girl hug + "(})" + girl_hug.gif + + + + Girl + "(x)" + girl.gif + + + + Agree (Thumbs up) + "(y)" + thumbs_up.gif + + + + Disagree (Thumbs down) + "(n)" + thumbs_down.gif + + + + Wu-Tang Logo + "(WU)" + wu.gif + 1 + true + + + + Hahaha + "xD" + hahaha.gif + 1 + + + + fingerscrossed not in msn webpage + "(yn)" + fingerscrossed.gif + 1 + + + + hifive not in msn webpage + "(h5)" + hifive.gif + 1 + + + + turtle not in msn webpage + "(tu)" + turtle.gif + + + + smilec not in msn webpage + ":`(" + smilec.gif + + + + brb not in msn webpage + "(brb)" + brb.gif + 1 + + + + handcuffs not in msn webpage + "(%)" + handcuffs.gif + + + + + game console (msn xbox) (not in msn webpage) + "(xx)" + console.gif + 1 + + + + + joint (msn cigarette) not in msn webpage + "(ci)" + cigarette.gif + yes + + + + asl not in msn webpage + "(?)" + asl.gif + + + + Rainbow not in msn webpage + "(r)" + rainbow.gif + + + + Sun not in msn webpage + "(#)" + sun.gif + + + + + diff --git a/smileys/settings_svg.xml b/smileys/settings_svg.xml new file mode 100644 index 0000000..1b43efe --- /dev/null +++ b/smileys/settings_svg.xml @@ -0,0 +1,87 @@ + + + + + Tux Skin by Steels + Based on Everaldo's Crystal Icons. + Contact: + steels@steels.no-ip.com + ese_waly@hotmail.com (msn) + http://steels.no-ip.com + Version 1.0 + + + + #EFEFEF + #CCCCCC + + + + + 16 + + + Smile + ":)" + ":-)" + + svg/emoticon_1.svg + + + + Wink, wink + ";)" + ";-)" + + svg/emoticon_2.svg + + + + Big smile + ":D" + ":-D" + + svg/emoticon_3.svg + + + + Sad + ":(" + ":-(" + + svg/emoticon_4.svg + + + + Crying + ".cry." + + svg/emoticon_5.svg + + + + Angry + ">)" + + svg/emoticon_6.svg + + + + Pfft + ":P" + ":-P" + + svg/emoticon_7.svg + + + + Ooh + ":O" + ":-O" + + svg/emoticon_8.svg + + + + + diff --git a/smileys/shades.gif b/smileys/shades.gif new file mode 100644 index 0000000000000000000000000000000000000000..7459332af2e6f491b9244243460aa8198714522f GIT binary patch literal 1267 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%0DMj?==ikP!GB(6j;1|b4m ziPUMR2q7U6R2Zkm0B@5`#gcql1~7^$S(jdhazB_tEpN++AjN^9%j}>_j02TH7FgRQ7nV{% zZ1O_H#m9k5`mhvIX=jn9Jt`_(|SkHoZXYmHKE zK0z7+h;c8LJ(lRtZa?(bfnL|9>5tmeD?a=gR&Mmq>@iNjGD zYpsXHyMt6qLvDI#*RMa^>)3pBUe-SCxET1#92)qJI5 z4{DaozwN);`tdK1%s4L%zw!Ih8~e0H?=%T_SKn@L+FZA#{=KU`XUN5_=e~W^d5FF} z8X+!JE&uEl-e^|4hQiH>tM)1C8u SPae5dwRyqg-OK8TjsF5qmZ2>G literal 0 HcmV?d00001 diff --git a/smileys/snail.gif b/smileys/snail.gif new file mode 100644 index 0000000000000000000000000000000000000000..77c261fd34487a27aa0d0562104e5f00db55b02c GIT binary patch literal 1127 zcmd_p{ZpC+0KoA_Bt=>=H{;BkYxBIN-PSp~?p#)-vGMHCwrI4dX=x z9zg*a2nYiSlvf9w8el4K0uKm^W8F+VWuhs_qE7EIxb_ z1HS>l-rin1olYi`nM@{?N^Nazg~Q=UB(k%!v$C?%*Vo5lv1BrtP$*2w4FVQ_FzrBY2yOo+u|r_)I$lkIl<7@# ze6`?L{p=JxaQ0eNz{-^jKo8y)&@p&to`ySFCPHyyff9K!^V*r-qp z2m}H?pU+{l7=+7a*$unqrgI28Wg?ipwwpPqK@nX$}2ju^9~+s&?a2&PGR23YY(}Y?A)B(c+q7%+)pokUU2-zNmzY%(RoP~0ak}8D8Hz^bn2*Q z_9fIOPheht-F@`yFdP1F*s=4d;&PI<{=4@Ag_U0fq_w@L<&rm>9+^YUkr$)|RZ~;E zH|QS~SK|_hfT|HS@GdFyA%HB1cgbsM$d})umGMeI7G@0-oS9P{=9Zk5ystY@a!!Qd u`)edkZvS&K{FA&g1)~yKt`T3IE!V1*$aC-$r8OTHeji__AI^aT)&Bx71KCml literal 0 HcmV?d00001 diff --git a/smileys/soccer.gif b/smileys/soccer.gif new file mode 100644 index 0000000000000000000000000000000000000000..3335c9dd3ba9e220a3218e0b8b5560d7d11c1979 GIT binary patch literal 1206 zcmZ?wbhEHb6k`x$c+SA^|NsB5U%$S6`}XkR!%a<1{r&y*_4PAn&V2s-`Hvqz{`~p# z=FOWAA3l8l{(ZxS4J%fx*s){B<;#~pefsqA;T z<;&5dNB#W#1Ox=+Nx)z#J4 zu3cNZcCCVfLReVXyW&>gnm3I(6!-S+m^S-2DChJ3Bke%F0qxQx6U33uCC_h=HlYwq@<*xqM}!?UY$O+-`G%3TU$FfH#a{&zo4KXBO@awCdS#> zSwlnP=l8GeHI;na++18-;^N}g*47ab5h5ZY-#&k;Dk?NLH+OJwu(Y%k6&3yV_3M@` zTdXWC`1tsAbaXT|HOB_$e)efYqresD5Fl^%nj(~$#$Dqb@z8bcCT=Si|O zI81bEJs_$RRU$CK@nER9enLve#e~KlapMe*HHnYe`egJuK^4yqjlfMUp2F(>3tT2D6>v?}3R{=3b5iQ2Or@x8HV+pq?RF4~+gHH& zS;dF<X?1fKG2wJrJ&1EVJaM;9n}?rwAF!+YH-k~cBS65;$Ad@diraBqw38$j9d=y1;}e&TZH3V3Nt+%Rc1xM~xp?btyVK;Yw=3b( PAwl8Nm#Pemj11NQxMGz; literal 0 HcmV?d00001 diff --git a/smileys/star.gif b/smileys/star.gif new file mode 100644 index 0000000000000000000000000000000000000000..a9f9e30c81ecfcc46701e3d806935c21e606dfce GIT binary patch literal 1087 zcmd^;|5MWi9L66Hjq%0qgLrfVaf1Xsj%->NaAXbL1UcwFNToBc8{`!!d6R=Wg>E$3 z35~mPga+5i#6-UQ;LetukvONzB$Q35OK7_-Hel|?U~|G~eD-es9X&t3?)Ag-!}ApF z+nbkPnS>a25xUeoeJd(>9 z#AKnH^Br3bXh zV?}TcYsjn#HG+%`c|earmMCv0etjE{hc(=N&5E1}k1}KhO@YRE-gbyBgF6`V!%K%p8VYf^Y*!feA4d@9UrZtX@0@iZqwO zTZu<3=DwFXyJeH1{bF7dztGqcn>JsV2Gfn&7+bAKnON^0L~xcC^2|C#&Ml zz2w(pCkG_AFX=vc<1@>3Lwv$JsrdsHeSzb}Qpw+WqbkHbbo9?>y>sC0s1-$SNN?GWIaDlzA=l(`n=2w_Cr`1e#(qk8T$2 d?<+l5(vp2<=siYqwRVH=&us_SZ&;6l{{WHhomT(= literal 0 HcmV?d00001 diff --git a/smileys/star2.gif b/smileys/star2.gif new file mode 100644 index 0000000000000000000000000000000000000000..ade87b139fddde8e43a0abbe1c78303ca0284f08 GIT binary patch literal 339 zcmZ?wbhEHb6lM@&Sjxcg|NsB5=TH6n@%>(u$G<g(AP?nQfkzj5W;rL%X#UEj=`azEDRd27Xkl;H2LUw+!NRY^`B z4e2ld0mv^5Y!wa-1r|I4{T>Sw96YQTSr0#)=^`O?WpPqsg2^W5_QXFPPD(Gfq~y$4 za#_Hu)pz}7U2z7r8QE*Soy5G&-VJ4-ae9!{a8?#>R%v=Q}t!n6N=$J&AzFlL!PV2vWfY4wL!B>2$eV zRGOG}GTD3nU2a=F}WHd`zftJT`4P&}BJsKw#h+uKDV zQBO~gOeX8^?^i07LqkI&BO{}uqb8FHf*_mCMr|Okt*zN02#rK?x!kt4w$9E@fj}UU zNCpQ7Su7TfMr&Bo^73CoK7-bb$6{OgeEZbY{{H^j?Bv>T{X$coLo46k+uPjSWHdLS5H(B&qrH_s zH%wjR<%~9!O&gRRw|irKjZdsX!GC2knLI8RRa5P-+h?qrS<#oPqKk{dY`d=KV1Iwv zZrL2F5~B*L;D6NN@l*5X~2WoKu{Ip>&Ab5<9py*}T}gP})*w-z2M z-MhP{f$r6%8Q1!XL5^6M9^Ugj-+8*Vv9j{etedsld|vPF_EYb{!OI~3Pl>=w|GfYN z`T)PcsI1&Vz|TK0BIyp0mR9K(9+@wKr}-axHTp_9>asfE@N0>;RfIInD@Tr}{sx2< zvru8MXhM9^TmUBG^yi`yNL_<{Jqd_Lg=XkO-h97wT11SiPSyI1D)j;k1q*j zrz4KUz_uthIk&i*pT4IB4JK;g0{F)O*AvC2^kA5D@^0{%KBqYN?8nvW zlW9RabH=l8z>eaQG@(b+-@BWY9}3e)RfQnN;w2%;krz+pCYw|1<5HlkWIPy7LXy!C`p|a3aevmb=FW|K#^rEbAdq+iOy{V z409|{^#YB|QCKB6b6E5F-VL%W;M-Nng{4+L*-VrZn;zzv0NCzp(g$kQZGg>mFaBdBXNU~wETj=&-u>oWvNVH3A zOqbiK;Xr+5MD-wO6__aETm)v2*h=*fN`_$Et4KUxqf)$#0I!sCOG3hcaaCp}CMF=) zjC5568LF34bPy|XB~hjby#`l~#d0+jGJsXgBp@3jlAUTXz?T!%Ehk$kDlpQG81&(6 z9PkXv9M*(Z*gHx2fy7chjx~$G1gVjW1qaS{;q-h0+`0y#as^B6RCf@`4YSJ#v}O}g znd{b5VNJAA!zFVy)L2eYM9G|xg#=1%fHF@}Ku!7#q{*qEnr?s+H!8FM;q(Z505Tzo z@xe^H)a@gpT~$P)T8U<%h97dv2;j7ggBp#H@oQWZCZl6)J6xvO5@8+67#mpbL)j*fjmt~}PKU9`V7c2c zMyWn?G9wTicg3%9#-phU5~37EkuurHrUHQ)f&1VV%ywfjMxhl8ZmQ-}&4LYGmkH5)N&ea{?I_IWy|BVMy(a{3i z?fmIt(X<7*L!Gx?K6LT%j1?oL^M$)3Qr)|_~6E3M^k^u=Up4_T~$(Y zVN*rj!&4v6d{}hpcJZbw?!2Ybwq8E@`jkh>bqiYxR`yidcV4b79xK?DJe!kaTJs;6 C^2yKu literal 0 HcmV?d00001 diff --git a/smileys/svg/01.svg b/smileys/svg/01.svg new file mode 100644 index 0000000..243a30d --- /dev/null +++ b/smileys/svg/01.svg @@ -0,0 +1,55 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/01.svg_ b/smileys/svg/01.svg_ new file mode 100644 index 0000000..b298ab0 --- /dev/null +++ b/smileys/svg/01.svg_ @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/02.svg b/smileys/svg/02.svg new file mode 100644 index 0000000..0ed39b4 --- /dev/null +++ b/smileys/svg/02.svg @@ -0,0 +1,89 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/02.svg_ b/smileys/svg/02.svg_ new file mode 100644 index 0000000..e1cbdfc --- /dev/null +++ b/smileys/svg/02.svg_ @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/BeOS_logo.svg b/smileys/svg/BeOS_logo.svg new file mode 100644 index 0000000..39cf5a0 --- /dev/null +++ b/smileys/svg/BeOS_logo.svg @@ -0,0 +1,33 @@ + + + + + + + +]> + + + + + + + + + diff --git a/smileys/svg/BeOS_logo.svg_ b/smileys/svg/BeOS_logo.svg_ new file mode 100644 index 0000000..e788189 --- /dev/null +++ b/smileys/svg/BeOS_logo.svg_ @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/smileys/svg/emoticon_1.svg b/smileys/svg/emoticon_1.svg new file mode 100644 index 0000000..cb9f6b3 --- /dev/null +++ b/smileys/svg/emoticon_1.svg @@ -0,0 +1,36 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_1.svg_ b/smileys/svg/emoticon_1.svg_ new file mode 100644 index 0000000..04d3c15 --- /dev/null +++ b/smileys/svg/emoticon_1.svg_ @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_2.svg b/smileys/svg/emoticon_2.svg new file mode 100644 index 0000000..200f289 --- /dev/null +++ b/smileys/svg/emoticon_2.svg @@ -0,0 +1,37 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_2.svg_ b/smileys/svg/emoticon_2.svg_ new file mode 100644 index 0000000..60d5c76 --- /dev/null +++ b/smileys/svg/emoticon_2.svg_ @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_3.svg b/smileys/svg/emoticon_3.svg new file mode 100644 index 0000000..7715990 --- /dev/null +++ b/smileys/svg/emoticon_3.svg @@ -0,0 +1,42 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_3.svg_ b/smileys/svg/emoticon_3.svg_ new file mode 100644 index 0000000..b29219a --- /dev/null +++ b/smileys/svg/emoticon_3.svg_ @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_4.svg b/smileys/svg/emoticon_4.svg new file mode 100644 index 0000000..0e89aea --- /dev/null +++ b/smileys/svg/emoticon_4.svg @@ -0,0 +1,36 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_4.svg_ b/smileys/svg/emoticon_4.svg_ new file mode 100644 index 0000000..f8d2d64 --- /dev/null +++ b/smileys/svg/emoticon_4.svg_ @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_5.svg b/smileys/svg/emoticon_5.svg new file mode 100644 index 0000000..0b59876 --- /dev/null +++ b/smileys/svg/emoticon_5.svg @@ -0,0 +1,45 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_5.svg_ b/smileys/svg/emoticon_5.svg_ new file mode 100644 index 0000000..c425c9c --- /dev/null +++ b/smileys/svg/emoticon_5.svg_ @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_6.svg b/smileys/svg/emoticon_6.svg new file mode 100644 index 0000000..f4d3459 --- /dev/null +++ b/smileys/svg/emoticon_6.svg @@ -0,0 +1,43 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_6.svg_ b/smileys/svg/emoticon_6.svg_ new file mode 100644 index 0000000..6929602 --- /dev/null +++ b/smileys/svg/emoticon_6.svg_ @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_7.svg b/smileys/svg/emoticon_7.svg new file mode 100644 index 0000000..89644f5 --- /dev/null +++ b/smileys/svg/emoticon_7.svg @@ -0,0 +1,62 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_7.svg_ b/smileys/svg/emoticon_7.svg_ new file mode 100644 index 0000000..c37b50d --- /dev/null +++ b/smileys/svg/emoticon_7.svg_ @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_8.svg b/smileys/svg/emoticon_8.svg new file mode 100644 index 0000000..9c1973c --- /dev/null +++ b/smileys/svg/emoticon_8.svg @@ -0,0 +1,36 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/emoticon_8.svg_ b/smileys/svg/emoticon_8.svg_ new file mode 100644 index 0000000..deeeb9d --- /dev/null +++ b/smileys/svg/emoticon_8.svg_ @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + diff --git a/smileys/svg/zeta-badge.svg b/smileys/svg/zeta-badge.svg new file mode 100644 index 0000000..8906687 --- /dev/null +++ b/smileys/svg/zeta-badge.svg @@ -0,0 +1,32 @@ + + + + +]> + + + + + + + + + + diff --git a/smileys/svg/zeta-badge.svg_ b/smileys/svg/zeta-badge.svg_ new file mode 100644 index 0000000..d71c3b2 --- /dev/null +++ b/smileys/svg/zeta-badge.svg_ @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/smileys/teeth_smile.gif b/smileys/teeth_smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..a9582b23a8c24318c86d1a31e9e49039ada1f23a GIT binary patch literal 1216 zcma)*|5MX-0Eb^pvF$?Kl!)V&F0<22lPMqq<|iPPGDR{H(`%q|0$M-{WmbbEQ6RqR z>B+$$ju62qo+vmO;D|3{47TxQ3^oSBbWFw=h%oFO{s%ojKR>*FcwV~#cY19LbA~ev z03l?mS3H!@>q+2rghL*V_AtnJP@LxIuJfk#@>!E^AdTug26YS!$*`7evfkV=d2`3e z?@*mY%Mo<{LA@N)S>(d5@0oqEm@0gS^yiQn9eHIY`XWo2w;~Fy$C=NiLd9_m|AP6p zXfoSp)8uN-EtMRCNh&10Kam%W^QP)oRv9rA^!@D66waJ6>gJn6h*dbN<MKG)tmw znj~2SI{DPhkbFw8oS3f;6|7WW!h|%=e9NmY1Xi6~9S71CL`;b@>L^t*R2P}^qx|8j zLuO?*(MJ=hk2C_^xxDTKjv)=?X_VovhwL0iDz^`mde%fhQ|L<`Ig%=9lhGK-vEF`* zJPDqx=UN**r{$j*?tVC@4y=h>Qh5ZU6`RN-jQ<7EmuL@%wQ?EJd)s>4hx0ijWt8>` zeL}pJs5tsO+&TzRtP^Q$;7@ABJ=dsqKAu&8C@|NGxpvlgC93yB z@dIZh52P2?253uyCNyGs7S))5kp)wY{>!M3;Hct31~IQj#|5VCg?YSJ+7*-)h6VJP#(Go2(9eV1Xg zfY>mmgmhscALSu1Dqx#{A_G->@w7?!PdHPS0CU$uv3Rb8BnBOPN*sdLGtl0^xDx$; zqcH}ONKSRo>#F}J8?eCZFM$3p?C5M4stz=J2R4;S)z@8E^tRiH!9lz8bk>?Zf}r{a z`xF}YSjX)||2LMc+y5(AeiC|$%kEsa*rF2I^>x9e2U%QyhV#axC1)&tCxTqK$J&_9 z)S`6Ppu)ZfiSI?J*xvCN>=azc5b}NlgH~0Z`EI~sCvIHvsc+T<=5C0U7Pqk0?h^!L zZBD+V6Mt2HcsBL@)GHegKR9g(9(>cqEllFO(tnhDb#p|!AnQ$zbJ9Vu6Fj; z(t(Z}M-7hozPG1MdS#P*6$Ki@HJ~)J&_8AQ2i^hm9jkYyv$rQXMGA@obJvH~oNviK zGj`4W)R3x0xi&@MS8~zy(=yR)aLMvKzssL>tHUE^hgcam`PK| zNjEGW%1-?VriRZq)y~uQxG@=99JsYFgVVT8^z&)-mUVX>w#dA!4v(I;6u^M7~rppxAEy^ZCM_xc>D f8gBQgW-C|oX)Kn#Z?vg?w{M9gi4$OF2cQ1{pa+C- literal 0 HcmV?d00001 diff --git a/smileys/thinking.gif b/smileys/thinking.gif new file mode 100644 index 0000000000000000000000000000000000000000..76c77714b709019bc0db34768f844da1304d9f76 GIT binary patch literal 2238 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 literal 0 HcmV?d00001 diff --git a/smileys/turtle.gif b/smileys/turtle.gif new file mode 100644 index 0000000000000000000000000000000000000000..fed153315f042a045599ee17a64e2f06456456ab GIT binary patch literal 1192 zcmchW;cwJr0LG8G&A|e0vP~o>FxUtP4s#m|p2?eCH(p28H%ntG)TOd+l-QV8D5N2c zHmpJ&4c1w;!UZo|W2&CyoK+ihl7^j7M?W;=gwx!IWw|UvNF;GaJ}hQB{|SGep5*uG z$&=@~190CnLoKnE*qvBxdvZIk3Hgi^`KBYWrO-BLvRp1F8BnQIM9fH*1Vwo7-aVOw zs;1t*e;`k3!-2fqMH^UJa}MnOg^9YZH;E=FbrK& zBq3lGHZ9QIsN2tJkcUf4OSY!)m{(+$WXZsFGZKcNBgq0=k%AyVBC;$i@Qkd&E2@%B zr%R<0Ndbsq&T$}0E-x=9DUj18$U>4wk#8HOLCJJZ;{*dcx|TLEmT~Cm2(MV*HAGRD zc#0^7A>hF5>}(qI8Aa?MI&_s!(n&yq&@(iOa81Q?6q-YjhNOUsfl~~EoGQ3>#!rOv1A^h%IvIfOWkC*qjGS?Mp2Zv01b-1i6smKf>GIwEaVJ1%IjgF zkQVvba+wrSR@WR=;B{V*1d62!u13;?XUUF=0RxbL?3Lakoi%jNl1L8uwo(oqM^ha| zDwj%t0*FW0z!atkmMBHxLZu>GGRsh&DJD@;z=A5Xt}dCTnIIC8XL@!fr-_a#AsVtO z7ZnN_kp~=+q(PK72?0WpBsl0f4qyn#kw~CQp<^pD5-EsDM_(C*@@={3TiKP&Q>7^S z=YM2(Y=!^65UX2`y?Bq>pO4TgNHn0;8^o~p>43bRCoB%;MSKf?^(Js(_VeC^YL}NYYrU`Vm5hWZaTGk z`151ub$jcJO*h68=emx@8&ma7JLZU*w)uwM&d%TOtf}8Ta$<(q z)HQx}-K!_3VSCl3p8ctY_|4O)H@Y5rxc$c8YVEex#`)A!M<-If@ml-_Fqv(Ty+2d literal 0 HcmV?d00001 diff --git a/smileys/umbrella.gif b/smileys/umbrella.gif new file mode 100644 index 0000000000000000000000000000000000000000..87a18959a83a0b556f66fdf4c0dc313afa6562b9 GIT binary patch literal 1139 zcmZ?wbhEHb6k`x$c+SA^|NsBbpFdr>bY=a<9jn%C+_-7`{{2TTUcB=7(UUJ^aZN^cX--~6c~x^q_vBf#7cO71?%cUc@87@w^XJd2*Kg|T+JnQA zBcn5t(+cwoYD&r)Dymv$&RKZp?!6yBeq6hLBPpZMFDTAGC_X48DJ&u_IxZ_IwJ;~I zvaYe~)amn|fZ+4zckkZ){P}aou6;g13BG}G{(ZXXVzEmbdKNcj(otR~Ii{YH#n$$g0iEt;@`*E~#i< zuyFa4Cr@6#e*NIV{kL!5K6(7Oqib?Tc6CN}RbF9TYx{)Tw{PFSfB(&!H{ZT}d-?L^ zq)9XK3z~BB>oT&catrJ08oDoEzVhYEmj@3XJbm)4yJtp0abreKRZc-&Nm6v8*4;`65fBx00S06rnc;x8WikkN7x~`(K zro@!OgNF{USh3>Z!Gn(*-O!NEpG79NFw0|yvcI7M_UJSI3Y zv-2ysOfYD4V&xWB3u0+dY-Zz?wkY}VfzgFSP{~y&#-PcCQ&>GvnqrkD`0l$J{3y)&ZkrRR{o>O!hJtuk!tNSmI=u}GOnyMAH zuII=k*VAHpv3qKMGO6{I-v_isxhv z#Z@UUg_boH7^PnNobiasceX`o(&LxH8WJqdk)2YmT2p*jm-^hbY}J~&%8B{mnxw0% ze)+Jji#yn*nk`n-xb{L&w{DSS3Af(P7n`{C#duO2_4obxbSwV=i}D$RH8$oGnEH_+`~{!;-sih59m~P-FT9p~X zI7ri2Q(Ex^cL6b6Qx`8%R|tVjXr3n!!LQ;GyR2l5N_>1S!W`rU@! zpNJ-r2sR4h&|k#vKf%=Jf;>;q*R2!5SK)pHdf0f~Kp_g+jGU&qYNNeI8LORZ z5!1*3jr7kYGFZA{5i!PV(G&sMQRdSdAOo;U={g?kaTfYG=*@tJ3$qYJfuSpCi(|@D zLDV2xx>?QERD}ypq3e5e9LI18tOICIfUJOR(thX;!%0iF{kV)rf z?b{j>ohqZCZgP<2;=wNZn-?nnE(~6Q)d*sR#o(%L+)S(v)>n|_p*{@HJ8J%pp$kvI z&^Oy8#(Kd|f+UUA5{2$r?K>Fn#n5fECxIW&YzlwZ?f=3m%<}FFp#BRRs>>2qD=2g3 zxv=tCZLL|hA9x;8t8Fr=j1{5W@V39^WK+CiC3n*U=gxPJ_yLS9d}{WR;3CiD(p$po z?vcD`hF2iXX?2GEapRUl;Y++?d+41k+e=HsO9mU$-4f(3{;5z)xmkHN>~o+|>MQd< z46<9~l~R7>>lGnItC9ufU5t-*aDxigadK2GUsdigUtD?d>gqj>$BdEc_pWv1Kgv!I zI3Mcl{q4H4kg_<(>tb$TL$b*}%*BtVm)tp^7cC2@KA@M@W$kd?bUMXgwsp_vZq9UY z_Rn-LDBarWync&lNa_|`uwr}Z&Mw)?&|;r>mFVok+jhSM{Cv`4=TXFqDF32(f%xXk z$2%Q7$|JX)TU-%Uy{|22YfFpAt~v>YwYq*NLy+D$QYu)}JfRh=rBW8=dQu$SC|>Qc zyb`YtW?}BSrE4CAdfQ%7_jpT!%CtGM(7^3JebGl9H_)r{FKtjJmFX_~r|KNNeKLF= neX7oM6Zr;T4h-|FqXsSywq-Cle(@5UPQM%6<;)-(8*Ka!yMlwb literal 0 HcmV?d00001 diff --git a/smileys/wilted_rose.gif b/smileys/wilted_rose.gif new file mode 100644 index 0000000000000000000000000000000000000000..9cffcba520702a8ce357e1e21e2381e027b55171 GIT binary patch literal 1038 zcmZ?wbhEHb6k`x$c+SA^|NsAg|Ni~?{rls)cdws4`~2a<-@kv~zkYpi_3Bk^Eei|t zHgvaNICSvG_wPTxeOuerzBns=eO2kYvfLHP5sT8}b}w1~tsC8LaGRegEOz&XYT5ZJye)tg>loS^KKSt;e=b z+c34HJFmYmWm|jglC@!M4c3VUnHh=FX;XU%!6+{%zCIP4l+QoW8!V zeR*ZWlKj#++0}EacAwl`yP&eRKdUVza6zQoEGNS`4!U!kbZ5I8A78in&!0cve|%qc zU{(L>?w*w$jZ3S0*0k0wtm$0Zdgbnw<|Xy*OR5?sX4FSGOm;V$<83x0z;1R<+RG=8 zfB*S?{o#$nmk!^1dhhM~w=dtmoVj^=!=jqIPw(A$cyrnQ6>ATzyLkER+1)$0&6s>} z_3~#AAO8LK_s7p4Q#Vd7ot5|F$B)H(7G+OPT()=F`P&!rrf0M*Z##PB*u^^+fe|_i zhz|iB1|R_C1qP1K42&Ey9vc=oHZlsS*__z0@Nm0;vez7sjR_513@khf0S6e4GII!N zL>yRf@L(&8tWAS};~^FF7`}Z$=#bTNLB`kkD3bvyVwpsl+e$$`6cCCc)=8ua(~cQISX~pF<%V68JH6ZP^u}~}XO6qe{_MwoF3Ym>f%McIN8ekl1&TaAb zX*|6eo&(1AI-yf?q#IE=j1z2H+|Q7tS;?~`qD)i^urAGpc?G|BuX9IT#Y7h_sE<=j5 zUgk9@X=}DmC*kP~;cZ1LDT?p%Xq5CuEsrD@KbKqr6tY4Isw@P7DV&_ z@~0qQJnt4P%MhjI#&VoZ;BE%LE5@b4-CgmlT}BPYAa4-o5=g7uI`DM?Z2{x}#td$a zP!#k>`h5lq&TjF-f*d=4tHvg?l^s|Et)yj_7d^D?cnA1u)9aT9~uv8O*|j7vExAT z(G?ex(!QOo4XBHCMBs`_#n6dY3PtbUR&5JX#O{fXU3>ZdjPy0@Bwiit>5oWDzp9UP zsTZBCu8g{$b-lP(o|QV%k^Erc;`NE%?vcs9cRni!FUwW#zaQ4Qvax8+n0=m24muNG zvHbS++^o$XmX9X3{V+4M`Xsz4n+WLsqNLO~Bl5f*c6{mQT!&d^6dlkcDDtDOsii06 zr&1g4<_~3`@IGJ@DH0j;rWe@Qu?+6>|?e@w(`q(gDNl9!JBiJ!>X{Rxzfc zivHr+e&@V^^(ZPf+Eene6H|8cznbmin-WS3V>dAs)fe}7_ovlh=;hh>cdb4g7*-Rd z5vMJmd?*V3GJofEM%?O()})dvnQh^(j^EP9WgfPU!|1Sl9d-%B6q1O`+d2bbYdL`# z71&f(%CJd>Eq^M5K;vBFZ@`GYgXwL-&pwgG2ManU6~!+){+E#sXtcUwNpPENGZ3SNvU9Q?O^x#T8vR zJ@J7!JpIk-3q#jFlqRqJr0Ak)>R?os_PgneXRddOME{+q|7Z+zjs;bil5{&d7hRAH zFH7ql8BlLO+B^D}7*2KOjh@R&8d4ozy2ZBf%yXY64(al#BU=~Nw#SYA)-iFmaKqP+ z8)r%)7p_Q`RIG}qEpN~3+S?X=WVARuN1?m>)!v^s4&KaYD1XwejP1~FSIyVl{xST( z(i5rEbn*#hro76$F#6J4q06)L2Odqx#p{lxzBiY@*>Eo?Wy#8cWm^KD9x`qFA}&pJ zXXM84FRHGq?)XBNlkN)K$KC}I3;S|FI+7&jgAVpUVtgv8+fsTo_O~i%A>qd}WX<*!h1+;J+|3ul^2B;|`Yq literal 0 HcmV?d00001 diff --git a/smileys/wu.gif b/smileys/wu.gif new file mode 100644 index 0000000000000000000000000000000000000000..925bf8bd7651de443b9b79e92af0289c2b8f353f GIT binary patch literal 681 zcmZ?wbhEHb6lM@+IL5&6|NsBfr%xLh8C|+`>Gtj0rKP3&_U(KB{{6FO&n8WpWNd8A z&CT80+snhlqphtS5fM>WS9j>pp}l+eIy*b_^YgQ^vc7rq=EH{%CMG8A?Ci|U%xr9I z0s;cIwzl{0-*0GW;Ns%q;NW0lVv>}U+_`h-{{8zE6&1H{-@a|zHWn6^#fukDm@wht z!-wtd?HwH*oSd9{_Uws|kC&2?ij9r6va&KWGZPjT_Vn~*WMm8u4vvb7s;sOmDJhYc zmtU}8!OE2@g@l9*4Gq_?U$3U7CN3_1=gu7s4Glj(znYpFRaMn#)28w9@s*X8y?psH zAt6CjRMg4I>Ey|iuV23|Dk|dT<;~B}U$bV7mX_A3Q>W6>(%!v$ckSA>BS(&G+O%oc zu3aZioR~OqqKb;jt5>g%9z6;SE2;w>1|R^%1q1uP28O2QmR3e4<|YqD$19H5ArpF45BB z)szyIRAk{`)z(oH)s(!Vt9MdLQ(wuzP?Jm5=O-b;U#J>r+uY0!oAS3pXZkr1Ixq5>=WW%X|M?zrATh% zaq$o_R7#RKs?0E9OUO1wP90V66@fhL4Ga?n6lQW{JyLNw!6iM9qbZ2dr9&=|&2#3V zh2ch8+6*BRXKbAyDyufF!=sSZ8|b-B4nj*(xu@&#$L;fA6mDyuv9)4