Mercurial > pidgin
comparison HACKING @ 1237:72692c70317e
[gaim-migrate @ 1247]
woo! i have a 10-ish page paper due in 11 hours on a book i haven't read yet. i'm in a writing mood.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Tue, 12 Dec 2000 12:56:53 +0000 |
parents | 4416ead31db7 |
children | ab5dd2c7e7f8 |
comparison
equal
deleted
inserted
replaced
1236:dcf9242241ee | 1237:72692c70317e |
---|---|
1 A lot of people have tried to hack gaim, but haven't been able to because | 1 A lot of people have tried to hack gaim, but haven't been able to because |
2 the code is just so horrid. Well, the code isn't getting better anytime | 2 the code is just so horrid. Well, the code isn't getting better anytime |
3 soon, so to help all you would-be hackers help out gaim, here's a brief | 3 soon (I hate GNU indent), so to help all you would-be hackers help out |
4 tutorial on how gaim works. I'll quickly describe the logical flow of | 4 gaim, here's a brief tutorial on how gaim works. I'll quickly describe |
5 things, then what you'll find in each of the source files. As an added | 5 the logical flow of things, then what you'll find in each of the source |
6 bonus, I'll try and describe as best I can how multiple connections and | 6 files. As an added bonus, I'll try and describe as best I can how multiple |
7 multiple protocols work. Hopefully that's enough to get most of you going. | 7 connections and multiple protocols work. Depending on how much I want |
8 to avoid my final tomorrow I may even describe other parts of gaim that | |
9 I particularly want to brag about. Hopefully that's enough to get most | |
10 of you going. | |
8 | 11 |
9 If you're going to hack gaim, PLEASE, PLEASE PLEASE PLEASE send patches | 12 If you're going to hack gaim, PLEASE, PLEASE PLEASE PLEASE send patches |
10 against the absolute latest CVS. I get really annoyed when I get patches | 13 against the absolute latest CVS. I get really annoyed when I get patches |
11 against the last released version, especially since I don't usually have | 14 against the last released version, especially since I don't usually |
12 a copy of it on my computer, and gaim tends to change a lot between | 15 have a copy of it on my computer, and gaim tends to change a lot between |
13 versions. (I sometimes get annoyed when they're against CVS from 3 days | 16 versions. (I sometimes get annoyed when they're against CVS from 3 days |
14 ago, but can't complain because it's usually my fault that I haven't | 17 ago, but can't complain because it's usually my fault that I haven't |
15 looked at the patch yet.) To get gaim from CVS (if you haven't already), | 18 looked at the patch yet.) To get gaim from CVS (if you haven't already), |
16 run the following commands: | 19 run the following commands: |
17 | 20 |
18 $ export CVSROOT=:pserver:anonymous@cvs.gaim.sourceforge.net:/cvsroot/gaim | 21 $ export CVSROOT=:pserver:anonymous@cvs.gaim.sourceforge.net:/cvsroot/gaim |
19 $ cvs login | 22 $ cvs login (hit enter as the password) |
20 (hit enter as the password) | |
21 $ cvs co gaim | 23 $ cvs co gaim |
22 (you'll see it getting all of the files) | 24 (you'll see it getting all of the files) |
23 $ cd gaim | 25 $ cd gaim |
24 $ ./gen | 26 $ ./gen |
25 | 27 |
26 You'll now have your normal gaim tree with ./configure and all. (If you | 28 You'll now have your normal gaim tree with ./configure and all. (If you |
27 want to make your life really simple, learn how CVS works. CVS is your | 29 want to make your life really simple, learn how CVS works. CVS is your |
28 friend.) | 30 friend.) To make a patch, just edit the files right there in that tree |
31 (don't bother with two trees, or even two copies of the same file). Then | |
32 when you're ready to make your patch, simply run 'cvs diff -u >my.patch' | |
33 and send it off. | |
29 | 34 |
30 There's one little thing that's just a pet peeve, and it's really stupid. | 35 There's one little thing that's just a pet peeve, and it's really stupid. |
31 In ./configure there's an --enable-debug option. This does two things: | 36 In ./configure there's an --enable-debug option. This does two things: |
32 compiles with -Wall, and prints debugging information to stdout. The | 37 compiles with -Wall, and prints debugging information to stdout. The |
33 debugging information is printed to the debug window (which can be turned | 38 debugging information is printed to the debug window (which can be turned |
34 on in the preferences) whether or not --enable-debug was selected. Most | 39 on in the preferences) whether or not --enable-debug was selected. Most |
35 of the information that's printed is useless anyway though; so the | 40 of the information that's printed is useless anyway though; so the |
36 --enable-debug option really doesn't do a whole lot. | 41 --enable-debug option really doesn't do a whole lot. |
37 | 42 |
38 This file was last modified by $Author: warmenhoven $ on $Date: 2000-11-16 02:35:58 -0500 (Thu, 16 Nov 2000) $. | 43 This file was last modified by $Author: warmenhoven $ on |
44 $Date: 2000-12-12 07:56:53 -0500 (Tue, 12 Dec 2000) $. | |
39 | 45 |
40 | 46 |
41 PROGRAM FLOW | 47 PROGRAM FLOW |
42 ============ | 48 ============ |
43 | 49 |
45 mostly just reading .gaimrc (handled by the functions in gaimrc.c) and | 51 mostly just reading .gaimrc (handled by the functions in gaimrc.c) and |
46 parsing command-line options. It then draws the login window by calling | 52 parsing command-line options. It then draws the login window by calling |
47 show_login, and waits for input. | 53 show_login, and waits for input. |
48 | 54 |
49 At the login window, when "Accounts" is clicked, account_editor() is | 55 At the login window, when "Accounts" is clicked, account_editor() is |
50 called. This then displays all of the users and various information about | 56 called. This then displays all of the users and various information |
51 them. If the user clicks the "Signon" button instead, serv_login is called. | 57 about them. If the user clicks the "Signon" button instead, serv_login |
58 is called. | |
52 | 59 |
53 When the "Sign on/off" button is clicked, serv_login is passed the | 60 When the "Sign on/off" button is clicked, serv_login is passed the |
54 username and the password for the account. If the password length is | 61 username and the password for the account. If the password length is |
55 zero (the password field is a character array rather than pointer so | 62 zero (the password field is a character array rather than pointer so it |
56 it will not be NULL) then the Signon callback will prompt for the | 63 will not be NULL) then the Signon callback will prompt for the password |
57 password before calling serv_login. serv_login then signs in the user | 64 before calling serv_login. serv_login then signs in the user using the |
58 using the appropriate protocol. We'll assume TOC for the rest of this | 65 appropriate protocol. We'll assume TOC for the rest of this discussion; |
59 discussion; Oscar has a lot of bad hacks to get it working that I don't | 66 even the libfaim guys get scared by oscar.c, and I'll talk about the |
60 even want to think about. | 67 PRPLs later. |
61 | 68 |
62 After you're signed in (I'll skip that discussion - I doubt many people | 69 After you're signed in (I'll skip that discussion - I doubt many people |
63 are going to change the login process, since it pretty much just follows | 70 are going to change the login process, since it pretty much just follows |
64 PROTOCOL), Gaim draws the buddy list by calling show_buddy_list, and | 71 PROTOCOL), Gaim draws the buddy list by calling show_buddy_list, and |
65 waits for input from two places: the server and the user. The first place | 72 waits for input from two places: the server and the user. The first |
66 it gets input from after signon is usually the server, when the server | 73 place it gets input from after signon is usually the server, when the |
67 tells Gaim which buddies are signed on. | 74 server tells Gaim which buddies are signed on. |
68 | 75 |
69 When there is information ready to be read from the server, toc_callback | 76 When there is information ready to be read from the server, toc_callback |
70 is called (by GDK) to parse the incoming information. On an UPDATE, | 77 is called (by GDK) to parse the incoming information. On an UPDATE, |
71 serv_got_update is called, which takes care of things like notifying | 78 serv_got_update is called, which takes care of things like notifying |
72 conversation windows of the update if need be; notifying the plugins; | 79 conversation windows of the update if need be; notifying the plugins; |
73 and finally, calling set_buddy. | 80 and finally, calling set_buddy. |
74 | 81 |
75 New connections happen the exact same way as described above. Each aim_user | 82 set_buddy is responsible for a lot of stuff, but most of it is done |
76 can have one gaim_connection associated with it. aim_user and gaim_connection | 83 implicitly. It's responsible for the sounds (which is just a call to |
77 both have a protocol field; gaim_connection's should be constant once it is | 84 play_sound), but the biggest thing it does is call new_group_show and |
78 set in the appropriate (protocol)_login function. There are lots of details | 85 new_buddy_show if necessary. There's only one group_show per group name, |
79 that are connected with multiple connections that are best explained by | 86 even between connections, and only one buddy_show per group_show per |
80 reading the code. | 87 buddy name, even between connections. (If that's not confusing enough, |
88 wait until I really start describing how the buddy list works.) | |
89 | |
90 New connections happen the exact same way as described above. Each | |
91 aim_user can have one gaim_connection associated with it. aim_user and | |
92 gaim_connection both have a protocol field; gaim_connection's should | |
93 be constant once it is set. (I'll talk about the gaim_connection struct | |
94 more later.) | |
81 | 95 |
82 When the user opens a new conversation window, new_conversation is called. | 96 When the user opens a new conversation window, new_conversation is called. |
83 That's easy enough. If there isn't a conversation with the person already | 97 That's easy enough. If there isn't a conversation with the person already |
84 open (checked by calling find_conversation), show_conv is called to | 98 open (checked by calling find_conversation), show_conv is called to |
85 create the new window. All sorts of neat things happen there, but it's | 99 create the new window. All sorts of neat things happen there, but it's |
97 Not much to say here, just a few basic functions. | 111 Not much to say here, just a few basic functions. |
98 | 112 |
99 aim.c: | 113 aim.c: |
100 This is where the main() function is. It takes care of a lot of the | 114 This is where the main() function is. It takes care of a lot of the |
101 initialization stuff, and showing the login window. It's pretty tiny | 115 initialization stuff, and showing the login window. It's pretty tiny |
102 and there's not really much to edit in it. Watch out for bad Oscar | 116 and there's not really much to edit in it. This has some of the most |
103 sign in hacks. | 117 pointless functions, like gaim_setup, which optionally turns off sounds |
118 on signon. A lot of this file should actually be part of other files. | |
104 | 119 |
105 away.c: | 120 away.c: |
106 This takes care of most of the away stuff: setting the away message | 121 This takes care of most of the away stuff: setting the away message |
107 (do_im_away); coming back (do_im_back); drawing the away window; | 122 (do_away_message); coming back (do_im_back); drawing the away window; |
108 etc. To be honest I haven't looked at this file in months. | 123 etc. |
109 | 124 |
110 browser.c: | 125 browser.c: |
111 Code for opening a browser window. Most of the code is trying to deal | 126 Code for opening a browser window. Most of the code is trying to deal |
112 with Netscape. The most important function here is open_url. Have fun. | 127 with Netscape. The most important function here is open_url. Have fun. |
128 (This file may give you problems with GTK 2.0, because it uses parts | |
129 of GDK that it's not supposed to know about.) | |
113 | 130 |
114 buddy.c: | 131 buddy.c: |
115 This takes care of not only nearly everything buddy-related (the buddy | 132 This takes care of not only nearly everything buddy-related (the |
116 list, the permit/deny lists, and the window), but also a lot of the | 133 buddy lists, the window, etc.), but also a lot of the code flow and |
117 code flow and util functions. Look for good things like find_buddy, | 134 util functions. Look for good things like find_buddy, set_buddy, |
118 set_buddy, and signoff() here. | 135 and signoff here. |
119 | 136 |
120 buddy_chat.c: | 137 buddy_chat.c: |
121 This takes care of the buddy chat stuff. This used to be a lot bigger | 138 This takes care of the buddy chat stuff. This used to be a lot bigger |
122 until the chat and IM windows got merged in the code. Now it mostly | 139 until the chat and IM windows got merged in the code. Now it mostly |
123 just takes care of chat-specific stuff, like ignoring people and | 140 just takes care of chat-specific stuff, like ignoring people and |
127 conversation.c: | 144 conversation.c: |
128 This is where most of the functions dealing with the IM and chat windows | 145 This is where most of the functions dealing with the IM and chat windows |
129 are hidden. It tries to abstract things as much as possible, but doesn't | 146 are hidden. It tries to abstract things as much as possible, but doesn't |
130 do a very good job. This is also where things like "Enter sends" and | 147 do a very good job. This is also where things like "Enter sends" and |
131 "Ctrl-{B/I/U/S}" options get carried out (look for send_callback). The | 148 "Ctrl-{B/I/U/S}" options get carried out (look for send_callback). The |
132 chat and IM toolbar (with the B/I/U/S buttons) are both built from the | 149 chat and IM toolbar (with the B/I/U/S buttons) are both built from |
133 same function, build_conv_toolbar. | 150 the same function, build_conv_toolbar. |
134 | 151 |
135 dialogs.c: | 152 dialogs.c: |
136 A massive file with a lot of little utility functions. This is where | 153 A massive file with a lot of little utility functions. This is where all |
137 all of those little dialog windows are created. Things like the warn | 154 of those little dialog windows are created. Things like the warn dialog |
138 dialog and the add buddy dialog are here. Not all of the dialogs in | 155 and the add buddy dialog are here. Not all of the dialogs in gaim are in |
139 gaim are in this file, though. But most of them are. This is also | 156 this file, though. But most of them are. This is also where do_import |
140 where do_import is housed, to import buddy lists. | 157 is housed, to import buddy lists. (The actual buddy list parsing code |
158 is in util.c for winaim lists and toc.c for gaim's own lists.) | |
141 | 159 |
142 gaimrc.c: | 160 gaimrc.c: |
143 This controls everything about the .gaimrc file. There's not really much | 161 This controls everything about the .gaimrc file. There's not really much |
144 to say about it; this is probably one of the better designed and easier | 162 to say about it; this is probably one of the better designed and easier |
145 to follow files in gaim. The important functions are towards the bottom. | 163 to follow files in gaim. The important functions are towards the bottom. |
146 | 164 |
147 gnome_applet_mgr.c: | 165 gnome_applet_mgr.c: |
148 A hideous creation from the days before I started working on gaim. Most | 166 This controls most things that are related to the applet. I don't like |
149 of it works, but it has functionsLikeThis. I hate looking at this | 167 looking at this file because it still has functionsLikeThis. But at |
150 file, but I'm too lazy to change the functions. The best functions | 168 least it doesn't have many of them anymore. Anyway, this file isn't |
151 are things like set_applet_draw_open, whose sole purpose is to set a | 169 very big because there's really not much difference between the panel |
152 global variable to TRUE. [ note 8/22/00 - I finally changed this file. ] | 170 version and the app version. |
153 | 171 |
154 gtkhtml.c: | 172 gtkhtml.c: |
155 This is really just one big hack. It started off as an HTML widget that | 173 This is really just one big hack. I recommend not looking at this |
156 was written for Gnome as far as I can tell. The current version is | 174 file if you want to save your sanity. (It's going to be replaced |
157 huge, requires way too many libs, and is too hard to upgrade to. But | 175 eventually anyway.) People have asked why we don't replace this with |
158 we've managed to hack this poor old version into basically what we | 176 GNOME's GtkHTML, or embed mozilla (yes, they were serious). There |
159 need it for. I recommend not looking at this file if you want to save | 177 are two reasons. The first is that doing that would cause gaim to |
160 your sanity. | 178 require 6 extra libraries that nobody needs or wants or has. The |
179 second is that we really don't need, or even want, a full-fledged | |
180 HTML viewer. We don't even want a normal HTML viewer because the text | |
181 that gets sent gets parsed and displayed different than normal HTML. | |
182 (Try inserting a newline and you'll see what I mean.) We should only | |
183 support about 12 tags, not the 50 that normal HTML supports. | |
161 | 184 |
162 gtkticker.c: | 185 gtkticker.c: |
163 Syd, our resident GTK God, wrote a GtkWidget, GtkTicker. This is that | 186 Syd, our resident GTK God, wrote a GtkWidget, GtkTicker. This is that |
164 widget. It's cool, and it's tiny. | 187 widget. It's cool, and it's tiny. |
165 | 188 |
170 | 193 |
171 idle.c: | 194 idle.c: |
172 This file used to be entirely #if 0'd out of existance. However, thanks | 195 This file used to be entirely #if 0'd out of existance. However, thanks |
173 to some very generous people who submitted patches, this takes care of | 196 to some very generous people who submitted patches, this takes care of |
174 reporting idle time (imagine that). It's a pretty straight-forward file. | 197 reporting idle time (imagine that). It's a pretty straight-forward file. |
198 This also takes care of the auto-away stuff. | |
175 | 199 |
176 multi.c: | 200 multi.c: |
177 This is the file that tries to take care of most of the major issues | 201 This is the file that tries to take care of most of the major issues |
178 with multiple connections. The best function in here by far is the | 202 with multiple connections. The best function in here by far is the |
179 account_editor(). auto_login() is also in here (I'm just reading | 203 account_editor(). auto_login() is also in here (I'm just reading multi.h |
180 multi.h now...); auto_login has problems. Someone please fix it. | 204 now...). account_editor is really the only function that the UI needs |
181 account_editor is really the only function that the UI needs to be | 205 to be concerned with. |
182 concerned with. If you want to remove multiconnectivity from gaim, | |
183 all you would really need to do is comment out any lines that make | |
184 reference to this function (there are only two - one in aim.c and one | |
185 in buddy.c). Or you could just run ./configure --disable-multi. | |
186 | 206 |
187 oscar.c: | 207 oscar.c: |
188 One big hack of copied code. This is supposed to be the libfaim tie-in | 208 One big hack of copied code. This is supposed to be the libfaim tie-in |
189 in gaim. Most of it is just copied straight from faimtest, the small | 209 in gaim. Most of it is just copied straight from faimtest, the small |
190 program that comes with libfaim. I'm not even sure how half of it works, | 210 program that comes with libfaim. I'm not even sure how half of it works, |
209 The important function in here is build_prefs, but the most useful | 229 The important function in here is build_prefs, but the most useful |
210 function is gaim_button. build_prefs draws the window, and calls | 230 function is gaim_button. build_prefs draws the window, and calls |
211 gaim_button probably 30 or 40 times. (I don't really wanna run grep | 231 gaim_button probably 30 or 40 times. (I don't really wanna run grep |
212 | wc to count.) This is where you add the toggle button for gaim | 232 | wc to count.) This is where you add the toggle button for gaim |
213 preferences. It's very simple, and if you look at a couple of the | 233 preferences. It's very simple, and if you look at a couple of the |
214 calls to gaim_button you'll figure it out right away. | 234 calls to gaim_button you'll figure it out right away. The new prefs |
235 window uses a CList instead of a Notebook, and there's a pretty bad | |
236 hack to get it to work. I won't tell you what though. | |
215 | 237 |
216 prpl.c: | 238 prpl.c: |
217 This file is what lets gaim dynamically load protocols, sort of. All of | 239 This file is what lets gaim dynamically load protocols, sort of. All |
218 the actual dlopen(), dlsym() stuff is in plugins.c. But this contains | 240 of the actual dlopen(), dlsym() stuff is in plugins.c. But this |
219 all of the functions that the protocol plugin needs to call, and manages | 241 contains all of the functions that the protocol plugin needs to call, |
220 all of the protocols. It's a pretty simple file actually. | 242 and manages all of the protocols. It's a pretty simple file actually. |
221 | 243 |
222 proxy.c: | 244 proxy.c: |
223 Adam (of libfaim glory) got bored one day and rewrote this file, so now | 245 Adam (of libfaim glory) got bored one day and rewrote this file, so |
224 everything actually works. The main function is proxy_connect, which | 246 now everything actually works. The main function is proxy_connect, |
225 figures out which proxy you want to use (if you want to use one at all) | 247 which figures out which proxy you want to use (if you want to use one |
226 and passes off the data to the appropriate function. This file should be | 248 at all) and passes off the data to the appropriate function. This file |
227 pretty straight-forward. | 249 should be pretty straight-forward. |
228 | 250 |
229 rvous.c: | 251 rvous.c: |
230 This was originally going to be the stuff for all of the Buddy Icon | 252 This was originally going to be the stuff for all of the Buddy Icon |
231 and Voice Chat stuff, but I got really sick of protocol hacking really | 253 and Voice Chat stuff, but I got really sick of protocol hacking really |
232 quick. Now it only houses the file transfer stuff, which only works | 254 quick. Now it only houses the file transfer stuff, which only works |
233 for TOC. | 255 for TOC. ("Works" being a very subjective statement. This file needs |
256 to be rewritten.) | |
234 | 257 |
235 server.c: | 258 server.c: |
236 This is where all of the differentiation between TOC and Oscar is | 259 This is where all of the differentiation between the different protocols |
237 done. Nearly everything that's network related goes through here | 260 is done. Nearly everything that's network related goes through here |
238 at one point or another. This has good things like serv_send_im and | 261 at one point or another. This has good things like serv_send_im and |
239 serv_got_update. Most of it should be pretty self-explanatory. | 262 serv_got_update. Most of it should be pretty self-explanatory. |
240 | 263 |
241 sound.c: | 264 sound.c: |
242 The main function in this file is play_sound, which plays one of 8 | 265 The main function in this file is play_sound, which plays one of 8 |
243 (maybe 9?) sounds based on preferences. All that the rest of the | 266 (maybe 9?) sounds based on preferences. All that the rest of the code |
244 code should have to do is call play_sound(BUDDY_ARRIVE), for example, | 267 should have to do is call play_sound(BUDDY_ARRIVE), for example, and |
245 and this file will take care of determining if a sound should be played | 268 this file will take care of determining if a sound should be played |
246 and which file should be played. | 269 and which file should be played. |
247 | 270 |
248 ticker.c: | 271 ticker.c: |
249 Syd is just so cool. I really can't get over it. He let me come | 272 Syd is just so cool. I really can't get over it. He let me come |
250 visit him at Netscape one day, and I got to see all of their toys | 273 visit him at Netscape one day, and I got to see all of their toys |
254 as cool as Syd. | 277 as cool as Syd. |
255 | 278 |
256 toc.c: | 279 toc.c: |
257 This handles everything TOC-related, including parsing gaim's buddy | 280 This handles everything TOC-related, including parsing gaim's buddy |
258 list. Most of this file is toc_callback, which parses the incoming | 281 list. Most of this file is toc_callback, which parses the incoming |
259 information from the server. I really don't like TOC though. | 282 information from the server. I really don't like TOC though. (I've spent |
283 waaayyyy too much time with TOC. I rewrote the signon process for this | |
284 file at one point, so that read was only called when data was pending. | |
285 Since then the TOC server has been blocking my IP (probably my own | |
286 stupid fault, sending bad strings or some such).) | |
260 | 287 |
261 util.c: | 288 util.c: |
262 There's not really a lot of cohesion to this file; it's just a lot of | 289 There's not really a lot of cohesion to this file; it's just a lot of |
263 stuff that happened to be thrown into it for no apparent reason. None | 290 stuff that happened to be thrown into it for no apparent reason. None |
264 of it is particularly tasty; it's all just utility functions. Just | 291 of it is particularly tasty; it's all just utility functions. Just |
265 like the name says. | 292 like the name says. |
266 | 293 |
267 | 294 |
295 HOW THE BUDDY LIST WORKS | |
296 ======================== | |
297 | |
298 The buddy list is a pain in the ass. Let me start off by saying that. The | |
299 most difficult part about getting gaim to do multiple connections was | |
300 the buddy list. In its current state it's very much like the UI for | |
301 0.10.x and earlier, which is what I was aiming for. However, the code | |
302 is completely different. And not much better. | |
303 | |
304 All of the buddy list stuff is in buddy.c, so you'll only have to have | |
305 that one file open (and possibly gaim.h for the struct definitions). There | |
306 are two sets of functions: those that deal with the buddy lists, and | |
307 those that deal with the window. (I say lists because each connection | |
308 has their own buddy list, independent of the others, even though the UI | |
309 merges them.) | |
310 | |
311 The buddy list functions work pretty much the same way they did before; | |
312 except now that each buddy and group belongs to a connection, things | |
313 like find_buddy take an additional argument, the connection you want to | |
314 search for the buddy in. Read gaim.h for a good list of them: find_buddy, | |
315 find_group, add_buddy, remove_buddy, remove_group. | |
316 | |
317 The window is a lot more fun. There's really only one function that | |
318 does anything interesting, and that's set_buddy. (There's also things | |
319 like build_edit_tree, but that's boring.) set_buddy is called by | |
320 serv_got_update (and should only be called by that function) any time | |
321 a user signs on, signs off, goes away, comes back, goes idle, etc, etc, | |
322 etc. Various things happen depending on the new state of the buddy. | |
323 | |
324 struct buddy has a member, present, which is set to either 0, 1, or | |
325 2. You can check if the buddy is online with "if (b->present)". This | |
326 becomes important. present is set to either 0 or 1 by serv_got_update, | |
327 or is not set at all. When the buddy is passed to set_buddy, if present | |
328 is 1 then set_buddy plays the BUDDY_ARRIVE sound, and sets present to 2, | |
329 to indicate it has already received notification of arrival. It then | |
330 does other signin-related stuff: setting the pixmap to the login icon; | |
331 updating the conversation windows; etc. | |
332 | |
333 The most important thing it does though, if a buddy is present, is it | |
334 checks for the existance of the appropriate group_show and buddy_show for | |
335 that buddy. Each buddy must belong to a group. group_shows are based on | |
336 name; there can only be one group_show for each group name. buddy_shows | |
337 are based both on name and on group_show; there can only be one buddy_show | |
338 in a group_show for each name. However, there can be two buddy_shows | |
339 with the same name as long as they have different group_shows. | |
340 | |
341 Each buddy_show has a GList of connections that has registered its related | |
342 buddy as being online. set_buddy makes sure that the connection that it's | |
343 being passed is part of the connlist for the buddy_show associated with | |
344 the struct buddy that it's passed (it helps to know your data structures). | |
345 | |
346 If a buddy logs off (b->present == 0), and a buddy_show exists for | |
347 that buddy, then set_buddy will play the logoff sound, change the icon, | |
348 remove the connection from the connlist for the buddy_show, etc. | |
349 | |
350 And that's how that works. For the buddy lists, connections own buddies; | |
351 for the window, the buddies own the connections. When the buddy_show | |
352 connlist count drops to zero it disappears from existance. | |
353 | |
354 | |
355 PLUGINS | |
356 ======= | |
357 | |
358 OK, so you want to load a plugin. You go through whatever UI (you | |
359 can read all about the UI in plugins.c or whereever). You finally get | |
360 to load_plugin, the meat of the plugins stuff (plugins can actually | |
361 call load_plugin themselves to load other plugins). load_plugin | |
362 is passed the full path to the plugin you want to load | |
363 (e.g. /usr/local/lib/gaim/irc.so). | |
364 | |
365 load_plugin does a few things with that filename. The first is to see | |
366 if you've already loaded that plugin. If you have, load_plugin unloads | |
367 the one that is currently loaded. You might wonder why; it's because | |
368 the same plugin can't be loaded twice. If you call g_module_open on a | |
369 filename twice, both times it will return the same pointer, and both times | |
370 increment the reference count on the GModule * that it returns. This | |
371 means you really do have the same plugin twice, which fucks up the | |
372 callback system to no end. So it's better that you can only have it | |
373 loaded once at any given time. | |
374 | |
375 Now that we're assured that we don't have this particular plugin loaded | |
376 yet, we better load it. g_module_open, baby. Much more portable than | |
377 dlopen(). In fact, for Linux it actually is the equivalent of dlopen() | |
378 (you can read the gmodule source and see for yourself). There's only one | |
379 quirk. It always logically ORs the options you pass with RTLD_GLOBAL, | |
380 which means that plugins share symbols. I haven't figured out yet if | |
381 this means just functions or variables too; but in either case make every | |
382 function and variable in your plugin static except for gaim_plugin_*(), | |
383 name(), and description(). It's good coding practice anyway. | |
384 | |
385 So, assuming we didn't get NULL back from g_module_open, we then make sure | |
386 it's a valid gaim plugin by looking for and calling gaim_plugin_init, | |
387 courtesy g_module_symbol (g_module_symbol is actually what's portable | |
388 about gmodule as opposed to dl*; some BSD's require '_' prepended to | |
389 symbol names and g_module_symbol guarantees we do The Right Thing). | |
390 | |
391 Assuming we've found gaim_plugin_init and it hasn't returned non-NULL | |
392 to us, we then add it to our list of plugins and go merrily about our way. | |
393 | |
394 So when do the callbacks happen?! plugin_event, baby, plugin_event. Any | |
395 time you want to trigger a plugin event simply call plugin_even with the | |
396 parameters to be passed to any event handlers and you're set. plugin_event | |
397 then makes sure that any plugins waiting for the event get passed the | |
398 arguments properly and passes it on to perl. | |
399 | |
400 Speaking of perl. If you really want to know how this works, you're | |
401 better off reading X-Chat's documentation of it, because it's better | |
402 than what I could provide. | |
403 | |
404 | |
268 MULTIPLE CONNECTIONS AND PRPLS | 405 MULTIPLE CONNECTIONS AND PRPLS |
269 ============================== | 406 ============================== |
270 | 407 |
271 OK, let's start with the basics. There are users. Each user is contained | 408 OK, let's start with the basics. There are users. Each user is contained |
272 in an aim_user struct, and kept track of in the aim_users GList (GSList?). | 409 in an aim_user struct, and kept track of in the aim_users GList (GSList?). |
273 Each aim_user has certain features: a username, a password, and user_info. | 410 Each aim_user has certain features: a username, a password, and user_info. |
274 It also has certain options, and the protocol it uses to sign on (kept as | 411 It also has certain options, and the protocol it uses to sign on (kept |
275 an int which is #define'd in prpl.h). The way the management of the users | 412 as an int which is #define'd in prpl.h). The way the management of the |
276 works is, there will (hopefully) only be one user for a given screenname/ | 413 users works is, there will (hopefully) only be one user for a given |
277 protocol pair (i.e. you may have two user warmenhoven's, but they'll both | 414 screenname/ protocol pair (i.e. you may have two user warmenhoven's, |
278 have a different protocol number). | 415 but they'll both have a different protocol number). |
279 | 416 |
280 Now then, there are protocols that gaim knows about. Each protocol is in | 417 Now then, there are protocols that gaim knows about. Each protocol is |
281 a prpl struct and kept track of in the protocols GSList. The way the | 418 in a prpl struct and kept track of in the protocols GSList. The way the |
282 management of the protocols is, there will only ever be one prpl per numeric | 419 management of the protocols is, there will only ever be one prpl per |
283 protocol. Each prpl defines a basic set of functions: login, logout, send_im, | 420 numeric protocol. Each prpl defines a basic set of functions: login, |
284 etc. The prpl is responsible not only for handling these functions, but also | 421 logout, send_im, etc. The prpl is responsible not only for handling |
285 for calling the appropriate serv_got functions (e.g. serv_got_update when a | 422 these functions, but also for calling the appropriate serv_got functions |
286 buddy comes online/goes offline/goes idle/etc). It handles each of these on | 423 (e.g. serv_got_update when a buddy comes online/goes offline/goes |
287 a per-connection basis. | 424 idle/etc). It handles each of these on a per-connection basis. |
288 | 425 |
289 So why's it called a PRPL? It stands for PRotocol PLugin. That means that | 426 So why's it called a PRPL? It stands for PRotocol PLugin. That means |
290 it's possible to dynamically add new protocols to gaim. However, all protocols | 427 that it's possible to dynamically add new protocols to gaim. However, |
291 must be implemented the same way: by using a prpl struct and being loaded, | 428 all protocols must be implemented the same way: by using a prpl struct |
292 regardless of whether they are static or dynamic. | 429 and being loaded, regardless of whether they are static or dynamic. |
293 | 430 |
294 Here's how struct gaim_connection fits into all of this. At some point the | 431 Here's how struct gaim_connection fits into all of this. At some point |
295 User (capitalized to indicate a person and not a name) will try to sign on | 432 the User (capitalized to indicate a person and not a name) will try to |
296 one of Their users. serv_login is then called for that user. It searches for | 433 sign on one of Their users. serv_login is then called for that user. It |
297 the prpl that is assigned to that user, and calls that prpl's login function, | 434 searches for the prpl that is assigned to that user, and calls that prpl's |
298 passing it the aim_user struct that is attempting to sign on. The prpl is then | 435 login function, passing it the aim_user struct that is attempting to sign |
299 responsible for seeing that the gaim_connection is created (by calling | 436 on. The prpl is then responsible for seeing that the gaim_connection |
300 new_gaim_connection), and registering it as being online (by calling | 437 is created (by calling new_gaim_connection), and registering it as |
301 account_online and passing it the aim_user and gaim_connection structs). At | 438 being online (by calling account_online and passing it the aim_user and |
302 that point, the aim_user and gaim_connection structs have pointers to each | 439 gaim_connection structs). At that point, the aim_user and gaim_connection |
303 other, and the gaim_connection struct has a pointer to the prpl struct that | 440 structs have pointers to each other, and the gaim_connection struct has |
304 it is using. The gaim_connections are stored in the connections GSList. | 441 a pointer to the prpl struct that it is using. The gaim_connections are |
305 The way connection management works is, there will always only be one | 442 stored in the connections GSList. The way connection management works is, |
306 gaim_connection per user, and the prpl that the gaim_connection uses will be | 443 there will always only be one gaim_connection per user, and the prpl that |
307 constant for the gaim_connection's life. | 444 the gaim_connection uses will be constant for the gaim_connection's life. |
308 | 445 |
309 So at certain points the User is going to want to do certain things, like | 446 So at certain points the User is going to want to do certain things, |
310 send a message. They must send the message on a connection. So the UI figures | 447 like send a message. They must send the message on a connection. So the UI |
311 out which gaim_connection the User want to send a message on (for our example), | 448 figures out which gaim_connection the User want to send a message on (for |
312 and calls serv_send_im, telling it which gaim_connection to use, and the | 449 our example), and calls serv_send_im, telling it which gaim_connection to |
313 necessary information (who to send it to, etc). The serv_ function then | 450 use, and the necessary information (who to send it to, etc). The serv_ |
314 calls the handler of the prpl of the connection for that event (that was way | 451 function then calls the handler of the prpl of the connection for that |
315 too many prepositions). OK, each prpl has a send_im function. Each connection | 452 event (that was way too many prepositions). OK, each prpl has a send_im |
316 has a prpl. so you call gc->prpl->send_im and pass it the connection and all | 453 function. Each connection has a prpl. so you call gc->prpl->send_im and |
317 the necessary info. And that's how things get done. | 454 pass it the connection and all the necessary info. And that's how things |
455 get done. | |
318 | 456 |
319 I hope some of that made sense. Looking back at it it makes absolutely no | 457 I hope some of that made sense. Looking back at it it makes absolutely no |
320 sense to me. Thank god I wrote the code; otherwise I'm sure I'd be lost. | 458 sense to me. Thank god I wrote the code; otherwise I'm sure I'd be lost. |