changeset 2863:0e70fe072ab4

[gaim-migrate @ 2876] bye bye my love bye bye committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Dec 2001 14:06:36 +0000
parents ad4057cb228f
children e22c09351e67
files HACKING PRPL
diffstat 2 files changed, 164 insertions(+), 210 deletions(-) [+]
line wrap: on
line diff
--- a/HACKING	Sun Dec 09 13:18:58 2001 +0000
+++ b/HACKING	Sun Dec 09 14:06:36 2001 +0000
@@ -4,15 +4,20 @@
 gaim, here's a brief tutorial on how gaim works. I'll quickly describe
 the logical flow of things, then what you'll find in each of the source
 files. As an added bonus, I'll try and describe as best I can how multiple
-connections and multiple protocols work. Depending on how much I want
-to avoid my final tomorrow I may even describe other parts of gaim that
-I particularly want to brag about. Hopefully that's enough to get most
-of you going.
+connections and multiple protocols work. Depending on how much I want to
+avoid my final tomorrow I may even describe other parts of gaim that I
+particularly want to brag about. Hopefully that's enough to get most of
+you going.
+
+If you don't know how event-driven programs work, stop right now. Gaim
+uses GTK+'s main loop (actually GLib's but I won't talk about how GTK
+works) and uses GLib functions for timeouts and socket notification. If
+you don't know GTK you should go learn that first.
 
 If you're going to hack gaim, PLEASE, PLEASE PLEASE PLEASE send patches
 against the absolute latest CVS. I get really annoyed when I get patches
-against the last released version, especially since I don't usually
-have a copy of it on my computer, and gaim tends to change a lot between
+against the last released version, especially since I don't usually have
+a copy of it on my computer, and gaim tends to change a lot between
 versions. (I sometimes get annoyed when they're against CVS from 3 days
 ago, but can't complain because it's usually my fault that I haven't
 looked at the patch yet.) To get gaim from CVS (if you haven't already),
@@ -20,37 +25,37 @@
 
 $ export CVSROOT=:pserver:anonymous@cvs.gaim.sourceforge.net:/cvsroot/gaim
 $ cvs login (hit enter as the password)
-$ cvs co gaim
-(you'll see it getting all of the files)
+$ cvs co gaim (you'll see it getting all of the files)
 $ cd gaim
 $ ./autogen.sh
 
-You'll now have your normal gaim tree with ./configure and all. (If you
-want to make your life really simple, learn how CVS works. CVS is your
-friend.) To make a patch, just edit the files right there in that tree
-(don't bother with two trees, or even two copies of the same file). Then
-when you're ready to make your patch, simply run 'cvs diff -u >my.patch'
-and send it off; either post it on sf.net/projects/gaim in the patches
-section, or email it to gaim@marko.net.
+You'll now have your normal gaim tree with ./configure and all (which
+./autogen.sh takes the liberty of running for you). (If you want to make
+your life really simple, learn how CVS works. CVS is your friend.) To make
+a patch, just edit the files right there in that tree (don't bother with
+two trees, or even two copies of the same file). Then when you're ready to
+make your patch, simply run 'cvs diff -u >my.patch' and send it off;
+either post it on sf.net/projects/gaim in the patches section, or email it
+to gaim@marko.net.
 
 This file was last modified by $Author: warmenhoven $ on
-$Date: 2001-11-01 13:50:39 -0500 (Thu, 01 Nov 2001) $. Do not expect any information contained
+$Date: 2001-12-09 09:06:36 -0500 (Sun, 09 Dec 2001) $. Do not expect any information contained
 within to be current or correct.
 
-Here's something new. Someone requested that I comment the code. No. I'm
-a lazy bastard, and I understand most of the code, so I don't need the
-comments. I understand that some of you do though. So give me the names
-of specific functions that you'd like commented and I'll see what I can
-do. It's more likely that those comments will be updated with the code
-than this file is, though even that is still unlikely.
+Here's something new. Someone requested that I comment the code. No. I'm a
+lazy bastard, and I understand most of the code, so I don't need the
+comments. I understand that some of you do though. So give me the names of
+specific functions that you'd like commented and I'll see what I can do.
+It's more likely that those comments will be updated with the code than
+this file is, though even that is still unlikely.
 
 
 CODING STYLE
 ============
 
-Coding styles are like assholes, everyone has one and no one likes
-anyone elses. This is mine and if you want me to accept a patch from
-you without getting annoyed you'll follow this coding style. :)
+Coding styles are like assholes, everyone has one and no one likes anyone
+elses. This is mine and if you want me to accept a patch from you without
+getting annoyed you'll follow this coding style. :)
 
 It would probably just be easier for me to include CodingStyle from the
 linux kernel source.
@@ -64,14 +69,14 @@
 for else statements should have both braces on the same line as the else
 (i.e. "} else {").
 
-No functionOrVariableNamesLikeThis. Save it for Java. Underscores are
-your friend. "tmp" is an excellent variable name. Hungarian style will
-not be tolerated. Go back to Microsoft.
+No functionOrVariableNamesLikeThis. Save it for Java. Underscores are your
+friend. "tmp" is an excellent variable name. Hungarian style will not be
+tolerated. Go back to Microsoft.
 
 I have a 105-char wide Eterm. Deal with it.
 
-NO goto. I'm very likely to refuse a patch if it makes use of goto. If
-you feel the need to use goto, you need to rethink your design and flow.
+NO goto. I'm very likely to refuse a patch if it makes use of goto. If you
+feel the need to use goto, you need to rethink your design and flow.
 
 
 PROGRAM FLOW
@@ -84,30 +89,24 @@
 
 At the login window, when "Accounts" is clicked, account_editor() is
 called. This then displays all of the users and various information
-about them. If the user clicks the "Signon" button instead, serv_login
-is called.
+about them. (Don't ask about what happens when "Sign On" is called. It's
+quite hackish. The only reason the login window is there anymore is to
+make it more palatable to people so used to WinAIM that they can't accept
+anything else.)
 
 When the "Sign on/off" button is clicked, serv_login is passed the
 username and the password for the account. If the password length is
 zero (the password field is a character array rather than pointer so it
 will not be NULL) then the Signon callback will prompt for the password
 before calling serv_login. serv_login then signs in the user using the
-appropriate protocol. We'll assume TOC for the rest of this discussion;
-even the libfaim guys get scared by oscar.c, and I'll talk about the
-PRPLs later.
+appropriate protocol.
 
-After you're signed in (I'll skip that discussion - I doubt many people
-are going to change the login process, since it pretty much just follows
-PROTOCOL), Gaim draws the buddy list by calling show_buddy_list, and
-waits for input from two places: the server and the user. The first
-place it gets input from after signon is usually the server, when the
-server tells Gaim which buddies are signed on.
-
-When there is information ready to be read from the server, toc_callback
-is called (by GDK) to parse the incoming information. On an UPDATE,
-serv_got_update is called, which takes care of things like notifying
-conversation windows of the update if need be; notifying the plugins;
-and finally, calling set_buddy.
+After you're signed in, Gaim draws the buddy list by calling
+show_buddy_list. Assuming the user has a buddy list (all buddy list
+functions are controlled by list.c; when you sign on do_import is called
+and that loads the locally saved list), the protocol calls
+serv_got_update, which sets the information in the appropriate struct
+buddy and then passes it off to set_buddy.
 
 set_buddy is responsible for a lot of stuff, but most of it is done
 implicitly. It's responsible for the sounds (which is just a call to
@@ -119,9 +118,13 @@
 
 New connections happen the exact same way as described above. Each
 aim_user can have one gaim_connection associated with it. aim_user and
-gaim_connection both have a protocol field; gaim_connection's should
-be constant once it is set. (I'll talk about the gaim_connection struct
-more later.)
+gaim_connection both have a protocol field. This is kind of confusing:
+gaim, except for the account editor screen and when the user signs on,
+ignores the user's protocl field, and only uses the connection's protocol
+field. You can change the connection's protocol field once it's created
+and been assigned a PRPL to use to change certain behavior (Oscar does
+this because it handles both AIM and ICQ). I'll talk about the
+gaim_connection struct more later.
 
 When the user opens a new conversation window, new_conversation is called.
 That's easy enough. If there isn't a conversation with the person already
@@ -165,14 +168,10 @@
 browser.c:
   Code for opening a browser window. Most of the code is trying to deal
   with Netscape. The most important function here is open_url. Have fun.
-  (This file may give you problems with GTK 2.0, because it uses parts
-  of GDK that it's not supposed to know about.)
 
 buddy.c:
-  This takes care of not only nearly everything buddy-related (the
-  buddy lists, the window, etc.), but also a lot of the code flow and
-  util functions. Look for good things like find_buddy, set_buddy,
-  and signoff here.
+  This takes care of the buddy list window and most things related to it.
+  It still has some functions that manage the list, but not many.
 
 buddy_chat.c:
   This takes care of the buddy chat stuff. This used to be a lot bigger
@@ -189,6 +188,9 @@
   chat and IM toolbar (with the B/I/U/S buttons) are both built from
   the same function, build_conv_toolbar.
 
+core.c:
+  This is the start of what will become the main() for gaim-core.
+
 dialogs.c:
   A massive file with a lot of little utility functions. This is where all
   of those little dialog windows are created. Things like the warn dialog
@@ -216,7 +218,8 @@
 
 gtkticker.c:
   Syd, our resident GTK God, wrote a GtkWidget, GtkTicker. This is that
-  widget. It's cool, and it's tiny.
+  widget. It's cool, and it's tiny. This is actually a really good example
+  widget for those of you looking to write your own.
 
 html.c:
   Don't ask my why this is called html.c. Most of it is just grab_url,
@@ -229,6 +232,21 @@
   reporting idle time (imagine that). It's a pretty straight-forward file.
   This also takes care of the auto-away stuff.
 
+list.c:
+  This file contains all of the routines for managing buddy lists,
+  including importing them from a file, saving them, adding and removing
+  buddies and groups, etc.
+
+md5.c:
+  Oscar, Yahoo, and MSN all require md5 hashing, so better to put it in
+  the core than have the same thing in three different places.
+
+module.c:
+  This contains all of the plugin code, except for the UI. This is what
+  actually loads the plugins, makes sure they're valid, has the code for
+  setting up plugin event handlers, and contains the plugin_event method
+  that gaim calls on events.
+
 multi.c:
   This is the file that tries to take care of most of the major issues
   with multiple connections. The best function in here by far is the
@@ -245,11 +263,7 @@
   implements the AIM module.
 
 plugins.c:
-  This is the "plugin plug", as the file states. This file is probably
-  the only file in all of gaim that at the top has all of the functions
-  and global and static variables named out for you. It makes reading
-  it a little easier, but not by much. A lot of the code in here deals
-  with the plugin window rather than the plugins themselves.
+  This contains the UI for the plugins dialog. It's mostly GTK.
 
 prefs.c:
   The important function in here is build_prefs, but the most useful
@@ -261,12 +275,6 @@
   window uses a CList instead of a Notebook, and there's a pretty bad
   hack to get it to work. I won't tell you what though.
 
-prpl.c:
-  This file is what lets gaim dynamically load protocols, sort of. All
-  of the actual dlopen(), dlsym() stuff is in plugins.c. But this
-  contains all of the functions that the protocol plugin needs to call,
-  and manages all of the protocols. It's a pretty simple file actually.
-
 proxy.c:
   Adam (of libfaim glory) got bored one day and rewrote this file, so
   now everything actually works. The main function is proxy_connect,
@@ -274,6 +282,12 @@
   at all) and passes off the data to the appropriate function. This file
   should be pretty straight-forward.
 
+prpl.c:
+  This file is what lets gaim dynamically load protocols, sort of. All
+  of the actual dlopen(), dlsym() stuff is in module.c. But this contains
+  all of the functions that the protocol plugin needs to call, and manages
+  all of the protocols. It's a pretty simple file actually.
+
 server.c:
   This is where all of the differentiation between the different protocols
   is done.  Nearly everything that's network related goes through here
@@ -301,65 +315,12 @@
   of it is particularly tasty; it's all just utility functions. Just
   like the name says.
 
-PRPL sources:
--------------
-
-ICQ (UDP v5)
-  All of the .c and .h files in here, with the exception of gaim_icq.c,
-  are part of ICQLib, by Bill Soudan and others. gaim_icq.c is what
-  interacts with gaim, and Eric wrote it. ICQLib is a fairly complete
-  implementation of the ICQ protocol, so if you want to add a new
-  feature you're probably going to be adding it to gaim_icq.c and not
-  to ICQLib.
-
-ICQ (2000)
-  This protocol doesn't exist yet. If you get really bored one day,
-  you can write it. It shouldn't be that hard since ICQ2000 uses Oscar,
-  so it should just be copying everything from oscar/ to here, and then
-  making small modifications to deal with various things. Have fun.
-
-IRC
-  Rob wrote irc.c, and since it is only one file it stands by itself.
-  All of the networking code is contained inside this file, as well as
-  the parts that interact with gaim.
-
-Jabber
-  jabber.c was written by Adam Fritzler (the guy that wrote libfaim),
-  and is maintained by Eric. The other .c and .h files belong to
-  libxode and libjabber, which were written by the Jabber developers.
+For the PRPLs, the only protocol whose "main" gaim file isn't the same as
+the name of the protocol is ICQ; for that it's gaim_icq.c. But ICQ is
+deprecated and you should be using Oscar for ICQ anyway.
 
-MSN
-  Rob wrote msn.c, and md5.c is a standard file. MSN doesn't use its
-  own library; all of the networking code is included inside of msn.c.
-
-Napster
-  Rob wrote napster.c, and since it is only one file it stands by
-  itself.
-
-Oscar
-  Most of these files are libfaim; the only one that's written by a Gaim
-  developer is oscar.c, and even that's questionable. oscar.c is mostly
-  copied straight from faimtest, the small program that comes with
-  libfaim.
-
-TOC
-  Everything TOC-related, more or less. All of it is in one big file, so
-  depending on your style that either makes things a lot easier or a lot
-  harder. Have fun with it. This protocol seems to break more easily
-  than any of the others, which seems odd to me. But oh well.
-
-Yahoo
-  All of the files in here were written by Eric. All of the .c and .h
-  files except yay.c are part of a library that Eric wrote, libyay.
-  yay.c is what interacts with gaim.
-
-Zephyr
-  zephyr.c is the only file in this directory by Eric; all the other
-  files are part of the Zephyr library from MIT.
-
-
-HOW THE BUDDY LIST WORKS
-========================
+HOW BUDDY LISTS WORK
+====================
 
 The buddy list is a pain in the ass. Let me start off by saying that. The
 most difficult part about getting gaim to do multiple connections was
@@ -367,18 +328,21 @@
 0.10.x and earlier, which is what I was aiming for. However, the code
 is completely different. And not much better.
 
-All of the buddy list stuff is in buddy.c, so you'll only have to have
-that one file open (and possibly gaim.h for the struct definitions). There
-are two sets of functions: those that deal with the buddy lists, and
-those that deal with the window. (I say lists because each connection
-has their own buddy list, independent of the others, even though the UI
-merges them.)
+There are two parts to the buddy list: the lists for the connections and
+the Buddy List window. list.c contains code to manage the lists themselves
+and buddy.c contains the code for the Buddy List window.
 
-The buddy list functions work pretty much the same way they did before;
-except now that each buddy and group belongs to a connection, things
-like find_buddy take an additional argument, the connection you want to
-search for the buddy in.  Read gaim.h for a good list of them: find_buddy,
-find_group, add_buddy, remove_buddy, remove_group.
+Each buddy needs to belong to a connection, it cannot belong to a
+"protocol" like in EveryBuddy. The reason is because when you are adding
+buddies, you tell the server who is on your buddy list so it can tell you
+about them; in order to tell the server, it needs to go out over a
+connection. Going out over all connections would not be good, so you need
+to specify which connection they go out on.
+
+Managing lists is therefore fairly easy, each group and buddy has an
+associated connection. Management functions like add_buddy/remove_buddy
+and add_group/remove_group all take a gaim_connection. These are all in
+list.c. They're boring.
 
 The window is a lot more fun. There's really only one function that
 does anything interesting, and that's set_buddy. (There's also things
@@ -475,10 +439,7 @@
 in an aim_user struct, and kept track of in the aim_users GList (GSList?).
 Each aim_user has certain features: a username, a password, and user_info.
 It also has certain options, and the protocol it uses to sign on (kept
-as an int which is #define'd in prpl.h). The way the management of the
-users works is, there will (hopefully) only be one user for a given
-screenname/ protocol pair (i.e. you may have two user warmenhoven's,
-but they'll both have a different protocol number).
+as an int which is #define'd in prpl.h).
 
 Now then, there are protocols that gaim knows about. Each protocol is
 in a prpl struct and kept track of in the protocols GSList. The way the
@@ -523,9 +484,71 @@
 I hope some of that made sense. Looking back at it it makes absolutely no
 sense to me. Thank god I wrote the code; otherwise I'm sure I'd be lost.
 
+
+WRITING PRPLS
+=============
+
+Start off with a protocol that you want to implement; make sure it has a
+number defined in prpl.h. If it doesn't, talk to Rob or Eric about adding
+it. *NEVER* use an unassigned number, not even for testing or personal
+use. It's possible that number will be used later by something else and
+that would cause quite a few head-scratchers.
+
+Start off with the following boiler plate:
+
+static struct prpl *my_protocol = NULL;
+
+void newproto_init(struct prpl *ret) {
+	ret->protocol = PROTO_NEWPROTO;
+
+	my_protocol = ret;
+}
+
+#ifndef STATIC
+
+char *gaim_plugin_init(GModule *handle)
+{
+        load_protocol(newproto_init, sizeof(struct prpl));
+        return NULL;
+}
+
+void gaim_plugin_remove()
+{
+        struct prpl *p = find_prpl(PROTO_NEWPROTO);
+        if (p == my_protocol)
+                unload_protocol(p);
+}
+
+char *name()
+{
+        return "New Protocol";
+}
+
+char *description()
+{
+        return PRPL_DESC("New Protocol");
+}
+
+#endif
+
+Replace all NEWPROTO things with your protocol name (e.g. PROTO_OSCAR
+instead of PROTO_NEWPROTO, oscar_init instead of newproto_init). Then
+populate your struct prpl; the most important function is actually name(),
+because without it, Gaim will most likely segfault. The second most
+important function is login(). Not all functions need to be implemented.
+
 There should be absolutely *ZERO* GTK in the PRPLs. PRPLs should *NEVER*
 say what the UI *looks* like, only what information needs to be there.
 There's currently an effort to get the GTK that is contained in the PRPLs
 directory out of there. If you submit a patch that adds GTK to those
 directories it's very likely to be refused, unless if I'm in a good mood
 and decide to relocate things for you. That's not likely.
+
+You're probably wondering how you can do certain things without GTK. Well,
+you're just going to have to make do. Rely on the UI, that's why it's
+there.  A PRPL should have absolutely ZERO interaction with the user, it
+should all be handled by the UI.
+
+Don't use the _options variables at all. The core should take care of all
+of that. There are several proto_opt fields that you can use on a per-user
+basis. Check out existing protocols for more details.
--- a/PRPL	Sun Dec 09 13:18:58 2001 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-Protocol Plugins. What EveryBuddy should have been.
-
-Each PRPL needs to have a unique identifier. In the pre-PRPL system TOC
-was 0 and Oscar was 1.  This identifier can be found in prpl.h. They
-are pre-assigned. PROTO_TOC is still 0, PROTO_OSCAR is still 1. The
-protocol_init function is expected to set the struct's protocol member to
-the appropriate value. If you want to write a new PRPL for gaim, please
-email one of the maintainers with the name of the protocol. We'll then
-reserve a number for it. Please do not use a number that has not been
-assigned to your protocol.
-
-The addition of PRPL to gaim means that gaim now supports multiple
-connections and multiple (and dynamically loadable) protocols.
-
-======
-
-I guess I should document how to write a PRPL.
-
-The first thing to do is to write your init function. It should be
-delcared
-
-void my_proto_init(struct prpl *p);
-
-You then fill in the members of the struct. See prpl.h for what they are.
-
-If you're going to load your protocol dynamically, put the function
-gaim_plugin_init(void *) in the file, and have it call
-
-	load_protocol(my_proto_init);
-
-and return NULL. Then compile as a plugin, load the .so file, and you're
-set. If you're going to load it statically, extern the my_proto_init
-function, and in prpl.c, call load_protocol.
-
-Your PRPL needs to have a login function, which ideally should set up a
-gdk_input watcher. When you want to indicate that the account is online,
-simply call account_online(struct gaim_connection *).  When there is
-information from the server, you should call the appropriate serv_got
-function (see gaim.h for a (partial?) list).
-
-When the UI wants to send something via the server, it will call the
-appropriate function that you set in your PRPL, if it's non-NULL. The
-only function that is absolutely critical is name. Without name gaim
-will probably crash. You don't even need login, just name. (You need
-login to do anything useful though.)
-
-======
-
-Erg. Now the fun part. The part that you would have never guessed if you
-weren't me. (I know that you wouldn't have guessed this stuff because
-it isn't painfully obvious to me. Use the Source, Luke.)
-
-Let's start with the basics. PRPLs shouldn't use GTK at all. If you use
-GTK I will hunt you down like the dog you are and kill you.
-
-You're probably wondering how you can do certain things without GTK. Well,
-you're just going to have to make do. Rely on the UI, that's why it's
-there.	A PRPL should have absolutely ZERO interaction with the user,
-it should all be handled by the UI.
-
-So let's talk about what that means in a practical way. Have a socket that
-you want notification on? Use gaim_input functions; they work just like
-the gdk_input functions. Want to add a timeout? g_timeout_add and
-g_source_remove. Want to ask a question? do_ask_dialog. Etc.
-
-Don't use the _options variables at all. The core should take care of all
-of that.
-
-Um. I'm sure there's more.