Mercurial > pidgin
comparison HACKING @ 16177:d88f0f320c9b
merge of '07fc4db9a3c2c12596e0354b8e7959aa847f966b'
and '2e6d324c725b3e6a2c803589bca3f0ac9b9790bf'
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Mon, 16 Apr 2007 00:44:33 +0000 |
parents | 9f793948154a c95641c98e47 |
children | d73ee2690376 |
comparison
equal
deleted
inserted
replaced
15938:2e3eba412412 | 16177:d88f0f320c9b |
---|---|
1 Lots of this is pretty grossly out of date... | 1 For information on hacking on Pidgin, Finch, or libpurple, see: |
2 Some of it might still be useful. For coding style, your | 2 http://developer.pidgin.im |
3 best bet is to browse through some of the files in src and | |
4 emulate what you see there. | |
5 --Mark | |
6 | |
7 | |
8 The majority of the below was written by Eric Warmenhoven way back in | |
9 antiquity. I have taken the liberty of attempting to PARTIALLY update | |
10 it. I still think its helpful, but use it at your own risk. | |
11 --Luke | |
12 | |
13 | |
14 A lot of people have tried to hack gaim, but haven't been able to because | |
15 the code is just so horrid. Well, the code isn't getting better anytime | |
16 soon (I hate GNU indent), so to help all you would-be hackers help out | |
17 gaim, here's a brief tutorial on how gaim works. I'll quickly describe | |
18 the logical flow of things, then what you'll find in each of the source | |
19 files. As an added bonus, I'll try and describe as best I can how multiple | |
20 connections and multiple protocols work. Depending on how much I want to | |
21 avoid my final tomorrow I may even describe other parts of gaim that I | |
22 particularly want to brag about. Hopefully that's enough to get most of | |
23 you going. | |
24 | |
25 If you don't know how event-driven programs work, stop right now. Gaim | |
26 uses GTK+'s main loop (actually GLib's but I won't talk about how GTK | |
27 works) and uses GLib functions for timeouts and socket notification. If | |
28 you don't know GTK+ you should go learn that first. | |
29 | |
30 If you're going to hack gaim, PLEASE, PLEASE PLEASE PLEASE send patches | |
31 against the absolute latest CVS. I get really annoyed when I get patches | |
32 against the last released version, especially since I don't usually have | |
33 a copy of it on my computer, and gaim tends to change a lot between | |
34 versions. (I sometimes get annoyed when they're against CVS from 3 days | |
35 ago, but can't complain because it's usually my fault that I haven't | |
36 looked at the patch yet.) To get gaim from CVS (if you haven't already), | |
37 run the following commands: | |
38 | |
39 $ export CVSROOT=:pserver:anonymous@cvs.sourceforge.net:/cvsroot/gaim | |
40 $ cvs login (hit enter as the password) | |
41 $ cvs co gaim (you'll see it getting all of the files) | |
42 $ cd gaim | |
43 $ ./autogen.sh | |
44 | |
45 You'll now have your normal gaim tree with ./configure and all (which | |
46 ./autogen.sh takes the liberty of running for you). (If you want to make | |
47 your life really simple, learn how CVS works. CVS is your friend.) To make | |
48 a patch, just edit the files right there in that tree (don't bother with | |
49 two trees, or even two copies of the same file). Then when you're ready to | |
50 make your patch, simply run 'cvs diff -u >my.patch' and post it on | |
51 sf.net/projects/gaim in the patches section. | |
52 | |
53 Some Documentation is available on the Gaim api if you run the command | |
54 $make docs | |
55 after running ./configure (or ./autogen.sh). You will need doxygen and | |
56 graphiz dot to generate these docs. | |
57 | |
58 CODING STYLE | |
59 ============ | |
60 | |
61 Coding styles are like assholes, everyone has one and no one likes anyone | |
62 elses. This is mine and if you want me to accept a patch from you without | |
63 getting annoyed you'll follow this coding style. :) | |
64 | |
65 It would probably just be easier for me to include CodingStyle from the | |
66 linux kernel source. | |
67 | |
68 Tab indents. I *HATE* 2-space indents, and I strongly dislike 8-space | |
69 indents. Use a tab character. I'm likely to refuse a patch if it has | |
70 2-space indents. | |
71 | |
72 K&R style for braces. Braces always go on the same line as the if, etc. | |
73 that they're associated with; the only exception is functions. Braces | |
74 for else statements should have both braces on the same line as the else | |
75 (i.e. "} else {"). | |
76 | |
77 No functionOrVariableNamesLikeThis. Save it for Java. Underscores are your | |
78 friend. "tmp" is an excellent variable name. Hungarian style will not be | |
79 tolerated. Go back to Microsoft. | |
80 | |
81 I have a 105-char wide Eterm. Deal with it. | |
82 | |
83 NO goto. I'm very likely to refuse a patch if it makes use of goto. If you | |
84 feel the need to use goto, you need to rethink your design and flow. | |
85 | |
86 | |
87 PROGRAM FLOW (just about every function name from here on down is wrong. | |
88 ============ but many of the ideas still apply under different names.) | |
89 | |
90 Before gaim does anything you can see, it initializes itself, which is | |
91 mostly just reading ~/.gaim/*.xml (handled by the functions in prefs.[ch]) | |
92 and parsing command-line options. It then draws the login window by | |
93 calling show_login, and waits for input. | |
94 | |
95 At the login window, when "Accounts" is clicked, account_editor() is | |
96 called. This then displays all of the users and various information | |
97 about them. (Don't ask about what happens when "Sign On" is called. It's | |
98 quite hackish. The only reason the login window is there anymore is to | |
99 make it more palatable to people so used to WinAIM that they can't accept | |
100 anything else.) | |
101 | |
102 When the "Sign on/off" button is clicked, serv_login is passed the | |
103 username and the password for the account. If the password length is | |
104 zero (the password field is a character array rather than pointer so it | |
105 will not be NULL) then the Signon callback will prompt for the password | |
106 before calling serv_login. serv_login then signs in the user using the | |
107 appropriate protocol. | |
108 | |
109 After you're signed in, Gaim draws the buddy list by calling | |
110 show_buddy_list. Assuming the user has a buddy list (all buddy list | |
111 functions are controlled by list.c; when you sign on do_import is called | |
112 and that loads the locally saved list), the protocol calls | |
113 gaim_prpl_got functions, which set the information in the appropriate | |
114 struct buddy and then passes it off to set_buddy. | |
115 | |
116 set_buddy is responsible for a lot of stuff, but most of it is done | |
117 implicitly. It's responsible for the sounds (which is just a call to | |
118 play_sound), but the biggest thing it does is call new_group_show and | |
119 new_buddy_show if necessary. There's only one group_show per group name, | |
120 even between connections, and only one buddy_show per group_show per | |
121 buddy name, even between connections. (If that's not confusing enough, | |
122 wait until I really start describing how the buddy list works.) | |
123 | |
124 New connections happen the exact same way as described above. Each | |
125 gaim_account can have one gaim_connection associated with it. gaim_account | |
126 and gaim_connection both have a protocol field. This is kind of confusing: | |
127 gaim, except for the account editor screen and when the user signs on, | |
128 ignores the user's protocl field, and only uses the connection's protocol | |
129 field. You can change the connection's protocol field once it's created | |
130 and been assigned a PRPL to use to change certain behavior (Oscar does | |
131 this because it handles both AIM and ICQ). I'll talk about the | |
132 gaim_connection struct more later. | |
133 | |
134 When the user opens a new conversation window, new_conversation is called. | |
135 That's easy enough. If there isn't a conversation with the person already | |
136 open (checked by calling find_conversation), show_conv is called to | |
137 create the new window. All sorts of neat things happen there, but it's | |
138 mostly drawing the window. show_conv is the best place to edit the UI. | |
139 | |
140 That's pretty much it for the quick tutorial. I know it wasn't much but | |
141 it's enough to get you started. Make sure you know GTK+ before you get too | |
142 involved. Most of the back-end stuff is pretty basic; most of gaim is GTK+. | |
143 | |
144 | |
145 SOURCE FILES (this should probly be utterly removed) | |
146 ============ | |
147 | |
148 about.c: | |
149 Not much to say here, just a few basic functions. | |
150 | |
151 account.[ch]: | |
152 This controls the GaimAccount struct, which stores information | |
153 on each account a user registers with gaim. Usernames, pass- | |
154 words, user info, alias, user specific options, and everything | |
155 else controlled from within the account editor (and then some) | |
156 are handled via this code. | |
157 | |
158 accountopt.[ch]: | |
159 Api and implemenation for account options. I'm not precisely | |
160 sure how this meshes with account.[ch] | |
161 | |
162 away.c: | |
163 This takes care of most of the away stuff: setting the away message | |
164 (do_away_message); coming back (do_im_back); drawing the away window; | |
165 etc. Away messages work really oddly due to multiple connections and | |
166 multiple protocols; I think there are really only two or three people | |
167 who know how it works and I don't think any of us know why it works | |
168 that way. | |
169 | |
170 blist.[ch]: | |
171 This takes care of the buddy list backend, the blist.xml file, | |
172 importing old buddy list files, and related things like | |
173 finding buddies and groups. buddies, contacts, and groups | |
174 are controlled from these files. | |
175 | |
176 buddy_chat.c: | |
177 This takes care of the buddy chat stuff. This used to be a lot bigger | |
178 until the chat and IM windows got merged in the code. Now it mostly | |
179 just takes care of chat-specific stuff, like ignoring people and | |
180 keeping track of who's in the room. This is also where the chat window | |
181 is created. | |
182 | |
183 conversation.c: | |
184 This is where most of the functions dealing with the IM and chat windows | |
185 are hidden. It tries to abstract things as much as possible, but doesn't | |
186 do a very good job. This is also where things like "Enter sends" and | |
187 "Ctrl-{B/I/U/S}" options get carried out (look for send_callback). The | |
188 chat and IM toolbar (with the B/I/U/S buttons) are both built from | |
189 the same function, build_conv_toolbar. | |
190 | |
191 core.c: | |
192 This is the start of what will become the main() for gaim-core. | |
193 | |
194 gtkdialogs.c: | |
195 A massive file with a lot of little utility functions. This is where all | |
196 of those little dialog windows are created. Things like the warn dialog | |
197 and the add buddy dialog are here. Not all of the dialogs in gaim are in | |
198 this file, though. But most of them are. This is also where do_import | |
199 is housed, to import buddy lists. (The actual buddy list parsing code | |
200 is in util.c for winaim lists and buddy.c for gaim's own lists.) | |
201 | |
202 gtkimhtml.c: | |
203 This is gaim's HTML widget. It replaced the old widget, GtkHtml (which | |
204 was different than GNOME's GtkHTML). It's self-contained (it doesn't | |
205 use any of gaim's code) and is actually a separate project from gaim | |
206 (but is maintained by Eric). | |
207 | |
208 idle.c: | |
209 This file used to be entirely #if 0'd out of existance. However, thanks | |
210 to some very generous people who submitted patches, this takes care of | |
211 reporting idle time (imagine that). It's a pretty straight-forward file. | |
212 This also takes care of the auto-away stuff. | |
213 | |
214 gtkmain.c: | |
215 This is where the main() function is. It takes care of a lot of the | |
216 initialization stuff, and showing the buddy list or account editor. | |
217 | |
218 md5.c: | |
219 Oscar, Yahoo, and MSN all require md5 hashing, so better to put it in | |
220 the core than have the same thing in three different places. | |
221 | |
222 module.c: | |
223 This contains all of the plugin code, except for the UI. This is what | |
224 actually loads the plugins, makes sure they're valid, has the code for | |
225 setting up plugin event handlers, and contains the plugin_event method | |
226 that gaim calls on events. | |
227 | |
228 prefs.c: | |
229 Read the documentation on this file. This handles the backend | |
230 side of prefs. | |
231 | |
232 proxy.c: | |
233 Adam (of libfaim glory) got bored one day and rewrote this file, so | |
234 now everything actually works. The main function is proxy_connect, | |
235 which figures out which proxy you want to use (if you want to use one | |
236 at all) and passes off the data to the appropriate function. This file | |
237 should be pretty straight-forward. | |
238 Except I STRONGLY suspect that time has broken this file. | |
239 | |
240 prpl.c: | |
241 This file is what lets gaim dynamically load protocols, sort of. All | |
242 of the actual dlopen(), dlsym() stuff is in module.c. But this contains | |
243 all of the functions that the protocol plugin needs to call, and manages | |
244 all of the protocols. It's a pretty simple file actually. | |
245 | |
246 server.c: | |
247 This is where all of the differentiation between the different protocols | |
248 is done. Nearly everything that's network related goes through here | |
249 at one point or another. This has good things like serv_send_im. Most of | |
250 it should be pretty self-explanatory. | |
251 | |
252 sound.c: | |
253 The main function in this file is play_sound, which plays one of 8 | |
254 (maybe 9?) sounds based on preferences. All that the rest of the code | |
255 should have to do is call play_sound(BUDDY_ARRIVE), for example, and | |
256 this file will take care of determining if a sound should be played | |
257 and which file should be played. | |
258 | |
259 util.c: | |
260 There's not really a lot of cohesion to this file; it's just a lot of | |
261 stuff that happened to be thrown into it for no apparent reason. None | |
262 of it is particularly tasty; it's all just utility functions. Just | |
263 like the name says. | |
264 | |
265 plugins/ticker/gtkticker.c: | |
266 Syd, our resident GTK+ God, wrote a GtkWidget, GtkTicker. This is that | |
267 widget. It's cool, and it's tiny. This is actually a really good example | |
268 widget for those of you looking to write your own. | |
269 | |
270 plugins/ticker/ticker.c: | |
271 Syd is just so cool. I really can't get over it. He let me come | |
272 visit him at Netscape one day, and I got to see all of their toys | |
273 (don't worry, I'm under an NDA). Anyway, this file is for the buddy | |
274 ticker. This is also a damn cool file because it's got all of the | |
275 functions that you'd want right up at the top. Someday I want to be | |
276 as cool as Syd. | |
277 | |
278 For the PRPLs, the only protocol whose "main" gaim file isn't the same as | |
279 the name of the protocol is ICQ; for that it's gaim_icq.c. But ICQ is | |
280 deprecated and you should be using Oscar for ICQ anyway. | |
281 | |
282 PLUGINS (read the plugins howto, this is really out of date) | |
283 ======= | |
284 | |
285 OK, so you want to load a plugin. You go through whatever UI (you | |
286 can read all about the UI in plugins.c or whereever). You finally get | |
287 to load_plugin, the meat of the plugins stuff (plugins can actually | |
288 call load_plugin themselves to load other plugins). load_plugin | |
289 is passed the full path to the plugin you want to load | |
290 (e.g. /usr/local/lib/gaim/irc.so). | |
291 | |
292 load_plugin does a few things with that filename. The first is to see | |
293 if you've already loaded that plugin. If you have, load_plugin unloads | |
294 the one that is currently loaded. You might wonder why; it's because | |
295 the same plugin can't be loaded twice. If you call g_module_open on a | |
296 filename twice, both times it will return the same pointer, and both times | |
297 increment the reference count on the GModule * that it returns. This | |
298 means you really do have the same plugin twice, which fucks up the | |
299 callback system to no end. So it's better that you can only have it | |
300 loaded once at any given time. | |
301 | |
302 Now that we're assured that we don't have this particular plugin loaded | |
303 yet, we better load it. g_module_open, baby. Much more portable than | |
304 dlopen(). In fact, for Linux it actually is the equivalent of dlopen() | |
305 (you can read the gmodule source and see for yourself). There's only one | |
306 quirk. It always logically ORs the options you pass with RTLD_GLOBAL, | |
307 which means that plugins share symbols. I haven't figured out yet if | |
308 this means just functions or variables too; but in either case make every | |
309 function and variable in your plugin static except for gaim_plugin_*(), | |
310 name(), and description(). It's good coding practice anyway. | |
311 | |
312 So, assuming we didn't get NULL back from g_module_open, we then make sure | |
313 it's a valid gaim plugin by looking for and calling gaim_plugin_init, | |
314 courtesy g_module_symbol (g_module_symbol is actually what's portable | |
315 about gmodule as opposed to dl*; some BSD's require '_' prepended to | |
316 symbol names and g_module_symbol guarantees we do The Right Thing). | |
317 | |
318 Assuming we've found gaim_plugin_init and it hasn't returned non-NULL | |
319 to us, we then add it to our list of plugins and go merrily about our way. | |
320 | |
321 So when do the callbacks happen?! plugin_event, baby, plugin_event. Any | |
322 time you want to trigger a plugin event simply call plugin_even with the | |
323 parameters to be passed to any event handlers and you're set. plugin_event | |
324 then makes sure that any plugins waiting for the event get passed the | |
325 arguments properly and passes it on to perl. | |
326 | |
327 Speaking of perl. If you really want to know how this works, you're | |
328 better off reading X-Chat's documentation of it, because it's better | |
329 than what I could provide. | |
330 | |
331 | |
332 MULTIPLE CONNECTIONS AND PRPLS | |
333 ============================== | |
334 | |
335 OK, let's start with the basics. There are users. Each user is contained | |
336 in an gaim_account struct, and kept track of in the gaim_accounts GSList. | |
337 Each gaim_account has certain features: a username, a password, and | |
338 user_info. It also has certain options, and the protocol it uses to sign | |
339 on (kept as an int which is #define'd in prpl.h). | |
340 | |
341 Now then, there are protocols that gaim knows about. Each protocol is | |
342 in a prpl struct and kept track of in the protocols GSList. The way the | |
343 management of the protocols is, there will only ever be one prpl per | |
344 numeric protocol. Each prpl defines a basic set of functions: login, | |
345 logout, send_im, etc. The prpl is responsible not only for handling | |
346 these functions, but also for calling the appropriate prpl_got functions | |
347 It handles each of these on a per-account basis. | |
348 | |
349 So why's it called a PRPL? It stands for PRotocol PLugin. That means | |
350 that it's possible to dynamically add new protocols to gaim. However, | |
351 all protocols must be implemented the same way: by using a prpl struct | |
352 and being loaded, regardless of whether they are static or dynamic. | |
353 | |
354 Here's how struct gaim_connection fits into all of this. At some point | |
355 the User (capitalized to indicate a person and not a name) will try to | |
356 sign on one of Their users. serv_login is then called for that user. It | |
357 searches for the prpl that is assigned to that user, and calls that prpl's | |
358 login function, passing it the gaim_account struct that is attempting to | |
359 sign on. The prpl is then responsible for seeing that the gaim_connection | |
360 is created (by calling new_gaim_connection), and registering it as | |
361 being online (by calling account_online and passing it the gaim_account and | |
362 gaim_connection structs). At that point, the gaim_account and gaim_connection | |
363 structs have pointers to each other, and the gaim_connection struct has | |
364 a pointer to the prpl struct that it is using. The gaim_connections are | |
365 stored in the connections GSList. The way connection management works is, | |
366 there will always only be one gaim_connection per user, and the prpl that | |
367 the gaim_connection uses will be constant for the gaim_connection's life. | |
368 | |
369 So at certain points the User is going to want to do certain things, | |
370 like send a message. They must send the message on a connection. So the UI | |
371 figures out which gaim_connection the User want to send a message on (for | |
372 our example), and calls serv_send_im, telling it which gaim_connection to | |
373 use, and the necessary information (who to send it to, etc). The serv_ | |
374 function then calls the handler of the prpl of the connection for that | |
375 event (that was way too many prepositions). OK, each prpl has a send_im | |
376 function. Each connection has a prpl. so you call gc->prpl->send_im and | |
377 pass it the connection and all the necessary info. And that's how things | |
378 get done. | |
379 | |
380 I hope some of that made sense. Looking back at it it makes absolutely no | |
381 sense to me. Thank god I wrote the code; otherwise I'm sure I'd be lost. | |
382 | |
383 | |
384 WRITING PRPLS | |
385 ============= | |
386 | |
387 Start off with a protocol that you want to implement; make sure it has a | |
388 number defined in prpl.h. If it doesn't, talk to Rob or Eric about adding | |
389 it. *NEVER* use an unassigned number, not even for testing or personal | |
390 use. It's possible that number will be used later by something else and | |
391 that would cause quite a few head-scratchers. | |
392 | |
393 Start off with the following boiler plate: | |
394 | |
395 static struct prpl *my_protocol = NULL; | |
396 | |
397 void newproto_init(struct prpl *ret) { | |
398 ret->protocol = PROTO_NEWPROTO; | |
399 | |
400 my_protocol = ret; | |
401 } | |
402 | |
403 #ifndef STATIC | |
404 | |
405 char *gaim_plugin_init(GModule *handle) | |
406 { | |
407 load_protocol(newproto_init, sizeof(struct prpl)); | |
408 return NULL; | |
409 } | |
410 | |
411 void gaim_plugin_remove() | |
412 { | |
413 struct prpl *p = find_prpl(PROTO_NEWPROTO); | |
414 if (p == my_protocol) | |
415 unload_protocol(p); | |
416 } | |
417 | |
418 char *name() | |
419 { | |
420 return "New Protocol"; | |
421 } | |
422 | |
423 char *description() | |
424 { | |
425 return PRPL_DESC("New Protocol"); | |
426 } | |
427 | |
428 #endif | |
429 | |
430 Replace all NEWPROTO things with your protocol name (e.g. PROTO_OSCAR | |
431 instead of PROTO_NEWPROTO, oscar_init instead of newproto_init). Then | |
432 populate your struct prpl; the most important function is actually name(), | |
433 because without it, Gaim will most likely segfault. The second most | |
434 important function is login(). Not all functions need to be implemented. | |
435 | |
436 There should be absolutely *ZERO* GTK+ in the PRPLs. PRPLs should *NEVER* | |
437 say what the UI *looks* like, only what information needs to be there. | |
438 There's currently an effort to get the GTK+ that is contained in the PRPLs | |
439 directory out of there. If you submit a patch that adds GTK+ to those | |
440 directories it's very likely to be refused, unless if I'm in a good mood | |
441 and decide to relocate things for you. That's not likely. | |
442 | |
443 You're probably wondering how you can do certain things without GTK+. Well, | |
444 you're just going to have to make do. Rely on the UI, that's why it's | |
445 there. A PRPL should have absolutely ZERO interaction with the user, it | |
446 should all be handled by the UI. | |
447 | |
448 Don't use the _options variables at all. The core should take care of all | |
449 of that. There are several proto_opt fields that you can use on a per-user | |
450 basis. Check out existing protocols for more details. |