summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--COPYING515
-rw-r--r--ChangeLog2923
-rw-r--r--INSTALL0
-rw-r--r--Makefile.am5
-rw-r--r--NEWS0
-rw-r--r--README0
-rw-r--r--configure.ac134
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/mc-dbus-iface.html296
-rw-r--r--doc/reference/Makefile.am74
-rw-r--r--doc/reference/mission-control-docs.sgml19
-rw-r--r--doc/reference/mission-control-overrides.txt0
-rw-r--r--doc/reference/mission-control-sections.txt182
-rw-r--r--doc/reference/mission-control.types9
-rw-r--r--doc/reference/tmpl/mc-account-monitor-priv.sgml16
-rw-r--r--doc/reference/tmpl/mc-account-monitor.sgml70
-rw-r--r--doc/reference/tmpl/mc-account-priv.sgml16
-rw-r--r--doc/reference/tmpl/mc-account.sgml361
-rw-r--r--doc/reference/tmpl/mc-client-lib-gen.sgml16
-rw-r--r--doc/reference/tmpl/mc-manager-priv.sgml16
-rw-r--r--doc/reference/tmpl/mc-manager.sgml92
-rw-r--r--doc/reference/tmpl/mc-profile.sgml219
-rw-r--r--doc/reference/tmpl/mc-protocol-priv.sgml16
-rw-r--r--doc/reference/tmpl/mc-protocol.sgml112
-rw-r--r--doc/reference/tmpl/mc.sgml23
-rw-r--r--doc/reference/tmpl/mission-control-signals-marshal.sgml16
-rw-r--r--doc/reference/tmpl/mission-control-unused.sgml256
-rw-r--r--doc/reference/tmpl/mission-control.sgml316
-rw-r--r--libmissioncontrol.pc.in12
-rw-r--r--libmissioncontrol/Makefile.am101
-rw-r--r--libmissioncontrol/mc-account-cli.c359
-rw-r--r--libmissioncontrol/mc-account-monitor-priv.h31
-rw-r--r--libmissioncontrol/mc-account-monitor.c440
-rw-r--r--libmissioncontrol/mc-account-monitor.h72
-rw-r--r--libmissioncontrol/mc-account-priv.h42
-rw-r--r--libmissioncontrol/mc-account.c2136
-rw-r--r--libmissioncontrol/mc-account.h182
-rw-r--r--libmissioncontrol/mc-manager-priv.h32
-rw-r--r--libmissioncontrol/mc-manager.c388
-rw-r--r--libmissioncontrol/mc-manager.h79
-rw-r--r--libmissioncontrol/mc-profile.c837
-rw-r--r--libmissioncontrol/mc-profile.h119
-rw-r--r--libmissioncontrol/mc-protocol-priv.h32
-rw-r--r--libmissioncontrol/mc-protocol.c367
-rw-r--r--libmissioncontrol/mc-protocol.h103
-rw-r--r--libmissioncontrol/mc.c50
-rw-r--r--libmissioncontrol/mc.h29
-rw-r--r--libmissioncontrol/mission-control-signals-marshal.list5
-rw-r--r--libmissioncontrol/mission-control.c1110
-rw-r--r--libmissioncontrol/mission-control.h208
-rw-r--r--libmissioncontrol/test.c491
-rw-r--r--mission-control.pc.in12
-rw-r--r--server/Makefile.am15
-rw-r--r--server/mc-server.c62
-rw-r--r--server/org.freedesktop.Telepathy.MissionControl.service.in3
-rw-r--r--src/Makefile.am110
-rw-r--r--src/mcd-chan-handler.c158
-rw-r--r--src/mcd-chan-handler.h42
-rw-r--r--src/mcd-channel.c796
-rw-r--r--src/mcd-channel.h106
-rw-r--r--src/mcd-connection.c1980
-rw-r--r--src/mcd-connection.h91
-rw-r--r--src/mcd-controller.c129
-rw-r--r--src/mcd-controller.h62
-rw-r--r--src/mcd-debug.c115
-rw-r--r--src/mcd-debug.h47
-rw-r--r--src/mcd-dispatcher-context.h138
-rw-r--r--src/mcd-dispatcher.c1185
-rw-r--r--src/mcd-dispatcher.h95
-rw-r--r--src/mcd-filtering-int.h17
-rw-r--r--src/mcd-main.c41
-rw-r--r--src/mcd-manager.c1065
-rw-r--r--src/mcd-manager.h92
-rw-r--r--src/mcd-master.c1150
-rw-r--r--src/mcd-master.h106
-rw-r--r--src/mcd-mission.c482
-rw-r--r--src/mcd-mission.h125
-rw-r--r--src/mcd-operation.c313
-rw-r--r--src/mcd-operation.h76
-rw-r--r--src/mcd-presence-frame.c884
-rw-r--r--src/mcd-presence-frame.h133
-rw-r--r--src/mcd-proxy.c226
-rw-r--r--src/mcd-proxy.h58
-rw-r--r--src/mcd-service.c789
-rw-r--r--src/mcd-service.h72
-rw-r--r--src/mcd-signals-marshal.list15
-rw-r--r--test/Makefile.am12
-rw-r--r--test/mc-client.c83
-rw-r--r--xml/Makefile.am1
-rw-r--r--xml/mcd-dbus-services.xml99
91 files changed, 23917 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..d9112e73
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+naba.kumar@nokia.com
+alberto.mardegan@nokia.com
+zeeshan.ali@nokia.com
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..c4792dd2
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,515 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+^L
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it
+does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper
+mail.
+
+You should also get your employer (if you work as a programmer) or
+your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..150a52fa
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2923 @@
+2007-03-09 Naba Kumar <naba.kumar@nokia.com>
+
+ * configure.ac: Version 4.17.
+
+ * configure.ac, server/Makefile.am: Fixed server conditional build
+ and simplified enable args.
+
+ * configure.ac: Removed date from version number.
+ * test/Makefile.am, configure.ac, server/Makefile.am,
+ Makefile.am: Fixed conditional build of server and test.
+
+2007-03-09 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac, server/Makefile.am,
+ server/com.nokia.chavo.mission_control.service.in,
+ server/org.freedesktop.Telepathy.MissionControl.service.in,
+ xml/mcd-dbus-services.xml, libmissioncontrol/mission-control.h,
+ src/mcd-service.c:
+ Change DBus paths to org.freedesktop.Telepathy.MissionControl.
+
+ * Makefile.am, com.nokia.chavo.mission_control.service.in,
+ configure.ac, server/Makefile.am, test/Makefile.am, test/mc-server.c:
+ Moving mc-server into a separate directory, and add a configure switch
+ to install it as the mission-control server. Move the DBus service
+ file to the same directory.
+
+2007-03-05 Naba Kumar <naba.kumar@nokia.com>
+
+ * configure.ac, debian/changlog: Bumped version to 4.16.
+
+ * (removed) LICENSE: Removed because it is redundant with COPYING file.
+
+ * test/mc-server.c, test/mc-client.c, debian/copyright,
+ src/mcd-master.h, src/mcd-presence-frame.h, src/mcd-mission.c,
+ src/mcd-controller.c, src/mcd-chan-handler.c, src/mcd-mission.h,
+ src/mcd-controller.h, src/mcd-chan-handler.h, src/mcd-connection.c,
+ src/mcd-operation.c, src/mcd-service.c, src/mcd-connection.h,
+ src/mcd-operation.h, src/mcd-service.h, src/mcd-channel.c,
+ src/mcd-manager.c, src/mcd-channel.h, src/mcd-dispatcher-context.h,
+ src/mcd-manager.h, src/mcd-proxy.c, src/mcd-main.c,
+ src/mcd-dispatcher.c, src/mcd-debug.c, src/mcd-proxy.h,
+ src/mcd-dispatcher.h, src/mcd-debug.h, src/mcd-master.c,
+ src/mcd-presence-frame.c, COPYING, libmissioncontrol/mc-protocol.c,
+ libmissioncontrol/mc-account.h, libmissioncontrol/mc-account-cli.c,
+ libmissioncontrol/mc.c, libmissioncontrol/mission-control.c,
+ libmissioncontrol/mc-account-monitor-priv.h,
+ libmissioncontrol/mc-profile.h, libmissioncontrol/mc-protocol.h
+ libmissioncontrol/mc.h, libmissioncontrol/mission-control.h,
+ libmissioncontrol/mc-manager.c, libmissioncontrol/mc-manager.h,
+ libmissioncontrol/mc-account-priv.h,
+ libmissioncontrol/mc-account-monitor.c, libmissioncontrol/test.c,
+ libmissioncontrol/mc-protocol-priv.h,
+ libmissioncontrol/mc-account-monitor.h, libmissioncontrol/mc-account.c,
+ libmissioncontrol/mc-manager-priv.h, libmissioncontrol/mc-profile.c:
+ Set lisence to LGPL.
+
+2007-03-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ Version 4.15.
+
+ * libmissioncontrol/mc-account-monitor.c:
+ Don't emit notifications when the avatar token changes; "avatar_id" is
+ the key to be monitored.
+
+ * libmissioncontrol/mc-account-priv.h:
+ * libmissioncontrol/mc-account.[hc]:
+ * src/mcd-connection.c:
+ Introduce a new GConf key for the accounts, "avatar_id", which is
+ meant to change whenever the avatar image changes.
+
+2007-02-28 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.14.
+
+ * libmissioncontrol/mission-control.c:
+ * xml/mcd-dbus-services.xml:
+ Make the D-Bus methods store the presence in an unsigned integer.
+
+ * libmissioncontrol/mc-account.c:
+ * src/mcd-connection.c:
+ Implement clearing of avatars.
+
+ * configure.ac:
+ * debian/control:
+ * libmissioncontrol/mission-control.[hc]:
+ * src/mcd-channel.[hc]:
+ * src/mcd-connection.c:
+ Support for libtelepathy version 0.0.50.
+
+2007-02-23 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account-monitor.c:
+ After emitting the "account-created" signal, check if the account is
+ already enabled and, in case, emit "account-enabled".
+
+2007-02-16 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account.c:
+ Make sure all the data has been flushed into the GConf DB before
+ enabling an account.
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.13.
+
+ * libmissioncontrol/mc-account.c:
+ Create account data directory if it not exists.
+
+ * src/mcd-connection.[hc], src/mcd-master.c:
+ Monitor account changes and call mcd_connection_account_changed() to
+ update the avatar.
+
+ * src/mcd-connection.c:
+ Connect the "destroy" signal only after making sure the proxy is
+ valid.
+
+2007-02-14 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.12.
+
+ * configure.ac:
+ * src/mcd-chan-handler.c:
+ Make the channel handler location path configurable.
+
+ * src/Makefile.am:
+ * src/mcd-service.c:
+ Set a prefix when calling dbus-binding-tool.
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.11.
+
+2007-02-13 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account.c:
+ Fix typo in accessing the GConf key.
+
+2007-02-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.10.
+
+2007-02-06 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account-monitor.h:
+ Add include guards.
+
+ * src/mcd-channel.[hc]:
+ Add mcd_channel_get_name() for getting the Telepathy name of the
+ channel.
+
+2007-02-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account.c:
+ * src/mcd-connection.c:
+ Allow setting NULL as avatar filename.
+
+2007-01-31 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account.[hc]:
+ * libmissioncontrol/mc-profile.[hc]:
+ Remove deprecated *_supports_invisible() APIs.
+
+ * libmissioncontrol/test.c:
+ * src/mcd-master.c:
+ Use new APIs for testing if invisible presence is supported.
+
+2007-01-30 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.9.
+
+ * libmissioncontrol/mc-account.c:
+ Avoid duplicating code too much.
+
+ * libmissioncontrol/mc-account.[hc]:
+ Add mc_account_set_avatar_mime_type() (only for MC).
+
+ * libmissioncontrol/mission-control.c:
+ Implement D-Bus call to MC's RemoteAvatarChanged method.
+
+ * src/mcd-connection.[hc], src/mcd-dispatcher.h, src/mcd-master.[hc],
+ src/mcd-service.c, xml/mcd-dbus-services.xml:
+ Implement remote_avatar_changed method, for retrieving our own avatar.
+
+ * libmissioncontrol/mc-account.c:
+ Fix avatar copy function, unset token when setting the avatar.
+
+2007-01-29 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.8.
+
+ * src/mcd-connection.c:
+ Set the avatar when connecting.
+
+ * libmissioncontrol/mc-account.[hc]:
+ Add mc_account_set_avatar_token(), to be used by MC when updating the
+ avatar.
+
+ * libmissioncontrol/mc-profile.[hc]:
+ Add "supports-avatars" capability to profiles.
+
+ * configure.ac:
+ Allow setting the account data base directory.
+
+ * libmissioncontrol/mc-account-priv.h:
+ * libmissioncontrol/mc-account.c:
+ Implement mc_account_{get,set}_avatar() APIs. On account
+ creation/deletion, create/delete the account data directory.
+
+2007-01-26 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.[hc]:
+ Add a TpConn parameter to mission_control_remote_avatar_changed API.
+
+ * doc/reference/mission-control-sections.txt:
+ * doc/reference/tmpl/mc-account.sgml:
+ * doc/reference/tmpl/mission-control.sgml:
+ * libmissioncontrol/mc-account.[hc]:
+ * libmissioncontrol/mission-control.[hc]:
+ Stubs for new APIs: mc_account_{set,get}_avatar() for setting/getting
+ the account avatar in GConf, and
+ mission_control_remote_avatar_changed() method for signalling that the
+ own avatar has been changed in the server.
+
+2007-01-23 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.7.
+
+ * src/mcd-connection.c: (on_presence_requested):
+ Disconnect the connection before closing it.
+
+2007-01-22 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.6.
+
+ * src/mcd-connection.[hc]:
+ * src/mcd-manager.c:
+ When disabling accounts, emit the AccountStatusChanged signal with the
+ reason "requested". Fixes NB#50067.
+
+ * libmissioncontrol/mission-control.c:
+ Don't make a D-Bus call whenever we want to know if MC is running.
+
+ * libmissioncontrol/mission-control.c:
+ Don't register a D-Bus filter for every instance; instead, install
+ only a global filter and maintain a list of the objects which must be
+ notified of the "ServiceEnded" signal.
+
+2007-01-19 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * doc/reference/mission-control-sections.txt:
+ * doc/reference/tmpl/mission-control-unused.sgml:
+ * doc/reference/tmpl/mission-control.sgml:
+ * libmissioncontrol/mission-control.h:
+ Documentation updates.
+
+ * libmissioncontrol/mission-control.c:
+ Added mission_control_free_account_statuses() API to free the array of
+ the account states returned in the callback function of
+ mission_control_get_current_status().
+
+2007-01-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.5.
+
+ * libmissioncontrol/mc-account-monitor.h:
+ Make apps which use only McAccountMonitor compile.
+
+2007-01-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.4.
+
+ * libmissioncontrol/mc-account.c: (_add_one_setting):
+ Add support for 32-bit integer parameters.
+
+ * libmissioncontrol/mission-control.[hc]:
+ * src/mcd-service.c:
+ * xml/mcd-dbus-services.xml:
+ Added a new method, mission_control_get_current_status(), for querying
+ the global status of MC: presence, connection status, and all
+ accounts' states too.
+
+ * src/mcd-connection.c: (_mcd_connection_setup):
+ Fix possible memleak.
+
+ * src/mcd-manager.c: (_find_connection_by_path):
+ Fix possible segfault.
+
+2007-01-17 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-account.h:
+ * libmissioncontrol/mc-profile.[hc]:
+ Mark some functions as deprecated, and remove some unused code.
+
+ * libmissioncontrol/mc-account-monitor.[hc]:
+ Add new API mc_account_monitor_get_supported_presences() for listing
+ all presences supported in any account.
+
+ * libmissioncontrol/Makefile.am:
+ * libmissioncontrol/mc-account.[hc]:
+ * libmissioncontrol/mc-profile.[hc]:
+ * libmissioncontrol/mission-control.h:
+ Add new APIs in McAccount and McProfile for retrieving the supported
+ presences, and to test if one presence state is supported.
+
+2007-01-11 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.3.
+
+ * libmissioncontrol/mission-control.[hc]:
+ Let the ..._request_channel() method return an operation id to be used
+ for cancelling the channel request.
+
+2007-01-11 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/*.[ch], libmissioncontrol/*.[ch], test/*.[ch], debian/copying,
+ COPYING, LICENSE: Updated license headers.
+
+2007-01-10 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.2.
+
+2007-01-09 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-profile.c:
+ * src/mcd-channel.c:
+ * src/mcd-connection.c:
+ * src/mcd-debug.c:
+ * src/mcd-dispatcher.c:
+ * src/mcd-master.c:
+ * src/mcd-service.c:
+ Memleak hunting!
+
+ * libmissioncontrol/mc-account-cli.c:
+ * libmissioncontrol/mc-account.[hc]:
+ * libmissioncontrol/mission-control.c:
+ * libmissioncontrol/test.c:
+ Rewritten McAccount's API: now the mc_account_get_{unique,display,
+ normalized}_name() functions return a const string, not to be freed.
+
+2007-01-05 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/rules:
+ * libmissioncontrol.pc.in:
+ * libmissioncontrol/mc-profile.c:
+ Turn the profiles' directory into a configure switch, and make it
+ available in pkg-config too.
+
+ * src/mcd-master.c:
+ Implement "default-presence" property.
+
+2007-01-04 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/*.[ch], libmissioncontrol/*.[ch], test/*.[ch], debian/copying,
+ COPYING: Added license headers.
+
+2007-01-04 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.[hc]:
+ Add a method for setting the default presence, instead of retrieving
+ it from a hardcoded GConf key.
+
+ * src/mcd-dispatcher.c:
+ * src/mcd-master.c:
+ * src/mcd-proxy.c:
+ Correct object disposal so all reference counts end up at zero.
+
+2007-01-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-chan-handler.c:
+ Remove unnecessary parameters, use g_error() for reporting errors and
+ aborting.
+
+2007-01-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.[hc]:
+ Make the operation_id counter a static variable, since it must be
+ unique in the context of a process. Remove its usage in functions
+ which are not supposed to be cancelled.
+
+ * Makefile.am:
+ * configure.ac:
+ * test/Makefile.am:
+ * test/mc-server.c:
+ Create a client and a server basic test applications.
+
+ * libmissioncontrol/mission-control.c:
+ Don't use a negative value for indicating an error in the connection
+ status.
+
+ * configure.ac:
+ * debian/changelog:
+ Version 4.1.
+
+ * libmissioncontrol/mission-control.c:
+ Don't free the GError after the callback invocation; let the callback
+ handler take care of it.
+
+ * src/mcd-service.c:
+ Free error after calling dbus_g_method_return_error().
+
+ * libmissioncontrol/mission-control.[hc]:
+ Make mission_control_cancel_channel_request return a gboolean.
+
+2006-12-29 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c:
+ Remove unused properties.
+
+ * src/mcd-channel.c:
+ * src/mcd-connection.c:
+ Since libtelepathy doesn't synthesize the StatusChanger and Closed
+ signals, take care of proxy destruction by monitoring the "destroy"
+ signal.
+
+2006-12-28 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.h, src/mcd-connection.[hc], src/mcd-manager.[hc],
+ src/mcd-master.[hc], src/mcd-service.c:
+ Unify request_channel and request_channel_with_string_handle
+ implementations, removing some duplicate code.
+
+ * doc/reference/tmpl/mission-control.sgml:
+ * libmissioncontrol/mc-account-monitor.c:
+ * libmissioncontrol/mission-control.c:
+ Don't emit the "Error" signal if MC is not running (the error is being
+ reported by the API anyway). Some documentation updates.
+
+ * src/mcd-service.c:
+ * xml/mcd-dbus-services.xml:
+ Remove the CancelLastRequest call completely.
+
+2006-12-27 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.[hc]:
+ Modify all synchronous functions by adding a GError parameter and
+ removing the "Error" signal. Modify asynchronous functions, and add a
+ callback function for error reporting.
+
+2006-12-19 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c:
+ Reset the abort reason when reconnecting. Don't use the "network
+ error" reason when we don't know the real reason for an early
+ disconnection. Fixes NB#50067.
+
+ * doc/mc-dbus-iface.html:
+ D-Bus docs updated.
+
+ * libmissioncontrol/mission-control.[hc]:
+ Removed mission_control_cancel_last_request() API, and all related
+ code.
+
+2006-12-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ Initiate auto-reconnection even in the case where we get disconnected
+ with no reason specified. Fixes NB#42727.
+
+ * src/mcd-connection.c: (_mcd_connection_setup):
+ If opening a new Telepathy connection fails, set the account status to
+ disconnected. This will help the clients to notify the user that we
+ couldn't connect, and also eliminates some critical warnings.
+
+2006-12-15 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Releasing version 4.0.
+
+ * libmissioncontrol/mission-control.c:
+ Emit Error signal whenever needed.
+
+ * src/mcd-service.c:
+ Correctly set up so that errors will be shown as g_warnings.
+
+ * configure.ac, debian/changelog,
+ libmissioncontrol/mission-control.c,
+ src/mcd-connection.c, src/mcd-manager.c:
+ Merge in all changes till version 3.17.
+
+ * libmissioncontrol/mission-control-signals-marshal.list,
+ libmissioncontrol/mission-control.[hc], src/mcd-channel.[hc],
+ src/mcd-connection.[hc], src/mcd-manager.[hc], src/mcd-master.[hc],
+ src/mcd-service.c, src/mcd-signals-marshal.list,
+ xml/mcd-dbus-services.xml:
+ Rewrite the D-Bus interface: remove the client-pid and serial
+ parameters from most calls, and instead consider the sender of the
+ D-Bus calls.
+ Turn the request_channel* functions into async calls.
+
+2006-12-12 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.15.
+
+2006-12-11 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_set_presence):
+ Add the weak pointer only after we are sure it's not NULL.
+
+2006-12-08 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * doc/reference/Makefile.am:
+ * doc/reference/mission-control.types:
+ Support for signals documentation.
+
+ * libmissioncontrol/mc-manager.c, libmissioncontrol/mc-profile.c,
+ libmissioncontrol/mc-protocol.c, libmissioncontrol/mc-protocol.h,
+ doc/reference/tmpl/*:
+ Add some API documentation.
+
+2006-12-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * debian/rules, libmissioncontrol/mc-account-monitor.c,
+ libmissioncontrol/mc-account.c, libmissioncontrol/mc.c,
+ libmissioncontrol/mission-control.c:
+ Documenting MC API.
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.14.
+
+ * src/mcd-presence-frame.c: (mcd_presence_frame_disconnect),
+ (mcd_presence_frame_class_init):
+ When we get disconnected, clear the requested presence.
+ Fixes NB#49144.
+
+2006-12-05 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_release_tp_connection):
+ Set the account status to disconnected, regardless whether the
+ Telepathy connection is there or not.
+
+ * src/mcd-service.c:
+ Reintroduce the handler for the status-actual signal from
+ McdPresenceFrame, but now exit only if there are no connections;
+ connections in disconnected state will prevent MC from exiting, since
+ they are supposed to be trying tor reconnect.
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb),
+ (_mcd_connection_setup):
+ Set the account status to "connecting" as soon as the connection gets
+ disconnected because of network error.
+
+ * doc/mc-dbus-iface.html, libmissioncontrol/mission-control.c,
+ src/mcd-service.c, src/mcd-signals-marshal.list,
+ xml/mcd-dbus-services.xml:
+ Add the last requested presence as a parameter for the StatusActual
+ DBus signal.
+
+2006-12-04 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c:
+ Instead of a fixed interval timer for reconnection, double the time at
+ every attempt (but make it no longer than half a hour anyway).
+
+ * src/mcd-connection.c:
+ If the connection is disconnected, don't abort it; instead, set up a
+ timer and try to reconnect it later. Fixes NB#49028.
+
+ * src/mcd-connection.c:
+ Don't leave the interface proxies around: store them as weak pointers.
+
+ * src/mcd-service.c:
+ Don't shutdown when the presence goes offline, since the cause could
+ be a network error.
+ Don't shutdown when status-actual signal is emitted with DISCONNECTED
+ state (again, could be a network error); remove the _on_status_actual
+ signal handler.
+ Instead, shutdown when McdService gets disconnected.
+
+ * src/mcd-manager.c:
+ Remove the on_account_status_changed() handler from Mcdmanager, since
+ it was useless (it was called when the connection had already been
+ removed).
+
+2006-12-01 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.c:
+ * libmissioncontrol/mission-control.h:
+ Move gtk-doc comments from .h to .c and clean them up.
+
+2006-11-30 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * Makefile.am:
+ * configure.ac:
+ * doc/*:
+ Add initial support for gtk-doc.
+
+ * xml/mcd-dbus-services.xml:
+ Naming all input parameters.
+
+ * doc/mc-dbus-iface.html:
+ Including short HTML documentation of the DBus MC interface.
+
+2006-11-29 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.13.
+
+ * libmissioncontrol/mission-control.[ch], src/mcd-service.c,
+ xml/mcd-dbus-services.xml:
+ Implement the StatusActual signal. Fixes NB#42727.
+
+2006-11-28 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.12.
+
+2006-11-24 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.c: (_mcd_master_init_account_monitoring),
+ (_mcd_master_dispose_account_monitoring), (_mcd_master_dispose):
+ Remove unused variables and release the account monitor on McdMaster
+ disposal.
+
+2006-11-22 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.c, src/mcd-master.h, src/mcd-service.c,
+ xml/mcd-dbus-services.xml:
+ Remove channel usage count test for determining whether to go
+ automatically offline. Instead, rewrite the
+ connect-all_with_default_presence() method to make it asyncronous and
+ store the DBus sender strings to determine if the processes which
+ requested the default presence are alive; if they are all dead, switch
+ back to offline presence (unless the user manually switched it to
+ online).
+
+2006-11-20 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-profile.c: (_mc_profile_load):
+ Retrieve localized display name for the profile. Fixes NB#47596.
+
+2006-11-20 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.c:
+ (mission_control_cancel_last_request):
+ Since cancel_last_request is broken, but someone might still be using
+ it, make it call cancel_last_channel_request.
+
+ * src/mcd-connection.c: (_mcd_connection_get_normalized_name),
+ (_mcd_connection_status_changed_cb):
+ When the connection is established, inspect the self handle and set
+ the normalized name into the account.
+
+2006-11-17 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.11.
+
+ * libmissioncontrol/mc-account-priv.h:
+ * libmissioncontrol/mc-account.c: (mc_account_get_normalized_name),
+ (mc_account_set_normalized_name):
+ * libmissioncontrol/mc-account.h:
+ Add mc_account_{get,set}_normalized_name() to the API.
+
+ * libmissioncontrol/mission-control.c: (mission_control_new):
+ Don't listen to every dbus message, but only to NameOwnerChange.
+
+ * libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control.h, src/mcd-connection.c,
+ src/mcd-connection.h, src/mcd-manager.c, src/mcd-manager.h,
+ src/mcd-master.c, src/mcd-master.h, src/mcd-service.c,
+ xml/mcd-dbus-services.xml:
+ Introduce new API: mission_control_cancel_channel_request() for
+ cancelling a channel request identified by the operation_id now
+ returned by mission_control_request_channel_with_string_handle().
+
+2006-11-15 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c:
+ Completely rewritten presence implementation. Correctly handles all
+ telepathy well-known statuses and uses much less memory.
+
+2006-11-14 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-manager.c: (_mcd_manager_nuke_connections):
+ Reset the error to NULL, or there'll be problem on the next iteration
+ of the loop.
+
+2006-11-13 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.10.
+
+ * src/mcd-manager.c: (on_presence_requested),
+ (mcd_manager_request_channel_with_string_handle):
+ * src/mcd-master.c:
+ (mcd_master_request_channel_with_string_handle):
+ * src/mcd-service.c:
+ (mcd_service_request_channel_with_string_handle):
+ Make sure we go online before attempting to request a channel.
+ Fixes NB#47136.
+
+2006-11-10 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.c: (dbus_filter_func),
+ (mission_control_dispose), (mission_control_class_init),
+ (mission_control_new):
+ Implemented "ServiceEnded" signal: this will be emitted whenever a
+ mission-control process terminates.
+
+2006-11-09 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mc-account-cli.c: Fixed account addition and
+ removal. Changed how parameters are specified.
+
+2006-11-09 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.9.
+
+ * libmissioncontrol/mc-account-cli.c: (show_help), (main):
+ Correct program name in mc-account help screen.
+
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_send):
+ Was still using "suppress-handler" property of McdChannel; change it
+ to "outgoing". Fixes NB#46811.
+
+2006-11-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-operation.c: (_mcd_operation_take_mission):
+ When reparenting, inherit all possible statuses from the parent
+ mission.
+
+2006-11-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.8.
+
+ * src/mcd-operation.c: (_mcd_operation_take_mission):
+ Inherit the "connected" status from the parent mission.
+
+2006-11-03 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-connection.c: Remove timer and idle sources
+ when connection object is destroyed. Fixes bug #46307
+
+2006-11-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * libmissioncontrol/mc-account.c: (_account_name_from_key):
+ * libmissioncontrol/test.c: (test_mc_account_list),
+ (test_account_monitor), (main):
+ Fix compilation warnings.
+
+2006-11-02 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mc-account-priv.h,
+ libmissioncontrol/mc-account-monitor.c,
+ libmissioncontrol/mc-account.c: Emit account-created signal
+ only when the account is 'complete' and do not enable
+ the account by default (let the accounts creation wizard
+ enable it when it is finished creating the account). Only
+ mark deleted accounts by a 'deleted' flag so that the account
+ is still usabled/accesible after deletion and set up a timer
+ to expunge deleted accounts after 2 secs. mc_accounts_list()
+ will now only return 'complete' accounts and not anything that
+ is found in gconf database. Accounts that have been marked
+ deleted are considered incomplete. Fixes NB#46297
+
+ * configure.ac, debian/control: Bumped version to 3.7
+
+2006-11-01 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (_mcd_channel_dispose):
+ * src/mcd-operation.c: (_mcd_operation_dispose),
+ (_mcd_operation_remove_mission):
+ Clean some more debug messages.
+
+ * src/mcd-debug.c: (mcd_debug_get_level):
+ * src/mcd-debug.h:
+ Add mcd_debug_get_level() function.
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.6.
+
+ * debian/rules:
+ Compile with G_DISABLE_CAST_CHECKS.
+
+ * configure.ac:
+ Add independent configure flags for checks/cast checks/asserts.
+
+ * src/mcd-debug.c: (mcd_debug_ref), (mcd_debug_unref),
+ (mcd_debug_print_tree), (mcd_debug_init):
+ * src/mcd-debug.h:
+ Introduce a MC_DEBUG environment variable to turn on/off some
+ debugging informations.
+
+2006-10-31 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mc-profile.c: (mc_profile_get_unique_name),
+ (mc_profile_get_configuration_ui), (mc_profile_get_display_name),
+ (mc_profile_get_icon_name), (mc_profile_get_branding_icon_name),
+ (mc_profile_get_supports_invisible), (mc_profile_get_protocol),
+ (mc_profile_get_protocol_name), (mc_profile_get_vcard_field),
+ (mc_profile_get_default_account_domain),
+ (mc_profile_is_default_for_vcard_field),
+ (mc_profile_get_capabilities), (mc_profile_get_default_setting):
+ Take out the calls to _mc_profile_load() from g_return* checks, since
+ we want it to be executed anyway.
+
+ * configure.ac:
+ Allow disabling of GLIB checks (G_DISABLE_ASSERT, G_DISABLE_CHECKS).
+
+2006-10-27 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-master.c: (mcd_master_set_offline_on_idle):
+ Minor cleanups, removed some unnecessary code.
+
+2006-10-26 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_release_tp_connection):
+ Removed some unused code about contacts' precences.
+
+2006-10-25 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.5.
+
+2006-10-24 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-manager.c: (abort_requested_channel),
+ (abort_requested_channels), (on_presence_requested):
+ If mission-control is going online because of some channel request
+ and the user cancels the connectivity setup, we must notify the UI
+ about these requested channels being aborted (fixes NB#43666).
+
+ * libmissioncontrol/mc-account.c: (mc_accounts_list):
+ Removed duplicate call to _mc_account_monitor_list() (fixes NB#39642).
+
+2006-10-23 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.4.
+
+ * src/mcd-master.c: (mcd_master_set_default_presence):
+ Avoid setting the default presence if we are disconnected but a
+ presence has already been requested (fixes #44124).
+
+ * src/mcd-connection.c: (presence_str_to_enum),
+ (_mcd_connection_set_fallback_presences),
+ (_mcd_connection_presence_enable), (_mcd_connection_set_presence):
+ Remodel the presence fallback structure, and return the actually
+ selected presence in the AccountStatusChanged signal (fixes #42138).
+ * src/mcd-presence-frame.c:
+ (_mcd_presence_frame_update_actual_presences),
+ (_mcd_presence_frame_update_actual_presence):
+ Correct the way the actual presence is computed.
+
+2006-10-20 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_new_channel_cb),
+ (on_capabilities_changed), (on_channel_capabilities_timeout),
+ (on_capabilities_timeout), (_mcd_connection_setup_capabilities),
+ (_mcd_connection_status_changed_cb),
+ (mcd_async_request_chan_callback),
+ (mcd_async_request_handle_callback):
+ Wait for capabilities: if a call fails within 5 seconds from the
+ connection establishment, wait for the contact's CapabilitiesChanged
+ signal and try again in case we receive any (fixes #36260).
+ For outgoing channels, ignore the NewChannel handler; instead, perform
+ the channel creation when the RequestChannel method returns.
+
+ * src/mcd-connection.c: (on_channel_capabilities_timeout),
+ (map_tp_error_to_mc_error), (mcd_async_request_chan_callback):
+ Report MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR only for StreamedMedia
+ channels (better fix for #43777).
+
+2006-10-20 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.3.
+
+ * libmissioncontrol/makefile.am:
+ Fix libmissioncontrol-config library version.
+
+2006-10-19 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.2.
+
+ * src/mcd-channel.c: (_mcd_channel_set_property),
+ (_mcd_channel_get_property), (mcd_channel_class_init),
+ (mcd_channel_new):
+ * src/mcd-channel.h:
+ * src/mcd-connection.c: (_mcd_connection_new_channel_cb),
+ (mcd_connection_request_channel),
+ (mcd_connection_request_channel_with_string_handle):
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_enter_state_machine):
+ Substitute the "suppress-handler" property from McdChannel with
+ "outgoing" and handle it accordingly.
+ Ignore unexpected NewChannel signals which have the suppress_handler
+ flag set (fixes #43446).
+
+ * src/mcd-dispatcher.c:
+ Fix some crashes that happened randomly when the channel was closed
+ shortly after creation.
+
+ * src/mcd-connection.c: (map_tp_error_to_mc_error):
+ Fix error code returned to the UI in case of missing capabilities
+ (fixes #43777).
+
+2006-10-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (mcd_channel_new):
+ * src/mcd-channel.h:
+ Use TelepathyConnectionHandleType instead of guint.
+
+ * src/mcd-master.c: (_on_dispatcher_channel_removed),
+ (mcd_master_set_offline_on_idle):
+ Don't go offline if channels other than text/streamed are closed.
+
+2006-10-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 3.1.
+
+2006-10-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_new_channel_cb),
+ (mcd_async_request_handle_callback):
+ Rewritten the check for existing channels: compare the channel type,
+ and not the channel handle type (fixes #43422).
+
+ * libmissioncontrol/mc-account-priv.h:
+ Revert the accounts path back to "/apps/telepathy/mc/accounts".
+
+2006-10-18 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.c: (mcd_master_get_online_connection_names):
+ Add a NULL pointer at the end of the connection names array (fixes
+ #43192).
+
+2006-10-17 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mc-account-priv.h: Fixed account gconf path.
+
+ * libmissioncontrol/mc-*.[ch]: Moved accounts/profiles/managers code
+ in libmissioncontrol.
+ * Makefile.am, src/Makefile.am, libmissioncontrol/Makefile.am,
+ xml/Makefile.am: Fixed Makefile.am files for proper installation and
+ packaging.
+ * configure.ac: Removed dependency on account library.
+ * libmissioncontrol.pc.in: Updated library flags.
+ * libmissioncontrol/mission-control.[ch], src/*.[ch]: Updated to use
+ new accounts api.
+
+2006-10-13 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (on_channel_members_changed),
+ (mcd_channel_new):
+ * src/mcd-connection.c: (_mcd_connection_presence_enable),
+ (_mcd_connection_new_channel_cb), (_mcd_connection_finalize),
+ (_mcd_connection_release_tp_connection):
+ * src/mcd-dispatcher.c: (mcd_dispatcher_get_channel_type_usage):
+ * src/mcd-manager.c: (on_presence_requested),
+ (_mcd_manager_finalize):
+ * src/mcd-mission.c: (_mcd_mission_set_mode), (_mcd_set_property):
+ * src/mcd-operation.c: (_mcd_operation_remove_mission):
+ * src/mcd-service.c: (_on_dispatcher_channel_removed),
+ (_on_dispatcher_channel_dispatched):
+ Remove some g_debug()s.
+
+2006-10-11 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 2.6.
+
+2006-10-10 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (_mcd_channel_release_tp_channel):
+ Don't close Telepathy Contact List channels.
+
+ * src/mcd-master.c:
+ (mcd_master_request_channel_with_string_handle):
+ Make sure the connectivity is up (or has been requested) before
+ attempting to request a channel (fixes #42822).
+
+2006-10-09 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version 2.5.
+
+2006-10-09 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (mcd_channel_class_init):
+ * src/mcd-connection.c: (mcd_async_request_handle_callback):
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb),
+ (channel_on_state_machine), (_mcd_dispatcher_send):
+ If the requested channel is already open, return it (works for both
+ incoming and outgoing channels).
+
+2006-10-06 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-manager.c: (_mcd_manager_set_presence_frame),
+ (_mcd_manager_dispose), (_mcd_manager_set_property):
+ Move the setting of the "presence-frame" property to a separate
+ function, since beacuse of the G_PARAM_CONSTRUCT_ONLY flag we were
+ not allowed to set it via a g_object_set().
+
+2006-10-06 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-proxy.c: (mcd_proxy_class_init):
+ Set McdProxy as a subclass of McdOperation.
+ Install "proxy-object" property.
+
+ * src/mcd-master.c: (_mcd_master_dispose), (mcd_master_init):
+ Create a proxy for forwarding McdMission signals to the McdDispatcher
+ and McdPresenceFrame.
+
+2006-10-05 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb),
+ (mcd_dispatcher_init):
+ Moved away all mode-setting stuff into the filters.
+
+2006-10-05 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Releasing MC 2.4.
+
+2006-10-05 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.c: (mcd_master_set_default_presence):
+ Conditions rewritten for better consistency.
+
+2006-10-05 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.c: (mcd_master_set_default_presence):
+ Don't allow setting the default presence if a presence
+ has already been requested.
+
+2006-10-04 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Releasing version 2.3
+
+2006-10-04 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-chan-handler.c: (_mcd_channel_handler_packer),
+ (_mcd_channel_handlers_read_conf_files):
+ * src/mcd-chan-handler.h:
+ * src/mcd-connection.c: (_mcd_connection_advertise_capabilities),
+ (_mcd_connection_status_changed_cb):
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_finalize),
+ (_build_channel_capabilities), (mcd_dispatcher_init),
+ (mcd_dispatcher_get_channel_capabilities):
+ * src/mcd-dispatcher.h:
+ Added support for channel handlers' capabilities.
+
+2006-10-04 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_remove_channel_watch),
+ (mcd_dispatcher_init):
+ Removed some old "exit_after_last_channel" stuff, which is now handled
+ in mcd-master under the name "offline_on_idle".
+
+2006-10-04 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ Version number++.
+
+ * src/mcd-master.c: (mcd_master_set_default_presence):
+ Add some more checks before setting "offline_on_idle".
+
+2006-10-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.c:
+ (mission_control_set_presence):
+ Don't ignore requests for offline presence if MC is not running: fixes
+ bug #42150.
+
+2006-10-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-service.c: (mcd_dispose), (mcd_service_init):
+ Disconnecting handlers. Also keep a reference to presence_frame and
+ dispatcher as long signals are connected to them.
+
+2006-10-03 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-master.c: (_on_dispatcher_channel_removed),
+ (_mcd_master_dispose), (mcd_master_init),
+ (mcd_master_set_offline_on_idle), (mcd_master_request_presence),
+ (mcd_master_set_default_presence):
+ If online presence was not requested directly by the user, when the
+ last conversation channel is closed set the presence to offline again.
+ Fixes bug #42013.
+
+2006-10-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * libmissioncontrol/mission-control.h:
+ Added declaration for mission_control_get_used_channels_count()
+ (closes bug #42020).
+
+2006-10-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * configure.ac:
+ * debian/changelog:
+ * debian/control:
+ New maintainer, new version.
+
+2006-10-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-manager.c: (requested_channel_process),
+ (on_presence_stable), (requested_channel_free),
+ (request_channel_delayed), (_mcd_manager_finalize),
+ (_mcd_manager_set_property), (mcd_manager_request_channel),
+ (mcd_manager_request_channel_with_string_handle):
+ If channel creation fails because the connection has not been set up
+ yet, store the channel request in a structure, and process it once the
+ "presence-stable" signal has been catched.
+
+ * src/mcd-presence-frame.c: (mcd_presence_frame_class_init),
+ (mcd_presence_frame_init), (_mcd_presence_frame_request_presence),
+ (_mcd_presence_frame_check_stable),
+ (_mcd_presence_frame_update_stable),
+ (mcd_presence_frame_set_account_status),
+ (mcd_presence_frame_is_stable):
+ * src/mcd-presence-frame.h:
+ * src/mcd-signals-marshal.list:
+ Add mcd_presence_frame_is_stable() function and "presence-stable"
+ signal.
+
+2006-10-02 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (mcd_async_request_handle_callback):
+ Check for errors must be done before using the function parameters,
+ since in case of error they may be unset.
+
+2006-09-29 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-manager.c: (_mcd_manager_dispose):
+ Use the "presence-frame" property to clean up in dispose.
+
+2006-09-29 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-service.c: Fix bug on error handling: g_propagate_error()
+ itself takes care of freeing the error.
+
+2006-09-27 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-connection.c: Restore channel object in cases where
+ handle == 0 in NewChannel events.
+
+ * src/mcd-service.c: Do not emit channel failed errors when
+ there is no requestor. Start shutdown timer if offline presence
+ is requested.
+
+ * src/mcd-connection.c, src/mcd-channel.c: Added type checks,
+ debug prints and ref accounting.
+
+ * src/mcd-dispatcher.c: Fixed memory corruption that would
+ lead to randon crashes when a channel is destroyed.
+
+ * src/mcd-channel.c: Close channel on abort.
+ * src/dispatcher.c: Fixed flag to set.
+
+2006-09-26 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ _mcd_connection_set_presence() must be called in all cases.
+
+2006-09-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-master.c:
+ Fix the gconf path name.
+ * src/mcd-mission.c: (_mcd_mission_set_mode):
+ Only set the mode when not already done.
+
+2006-09-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dispatcher.c: (mcd_dispatcher_get_channel_type_usage),
+ (_mcd_dispatcher_enter_state_machine),
+ (mcd_dispatcher_context_process):
+ Rename next_func_id to next_func_index.
+
+2006-09-26 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-presence-frame.c: Emit status changed and presence
+ changed in the right order.
+ * src/mcd-service.c: Do not emit CONNECTING state to the interface,
+ cause the ui doesn't handle it correctly.
+ * src/mcd-connection.c: Pass connection status reason correctly.
+
+2006-09-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-channel.c: (on_tp_channel_closed),
+ (_mcd_channel_set_property), (mcd_channel_get_members):
+ Correct an assertion and put one more.
+
+2006-09-25 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-channel.c: (mcd_channel_get_members):
+ Removed an unneeded if.
+
+2006-09-25 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (on_channel_members_changed),
+ (mcd_channel_new): Fix typo: signal "member-accepted" should be
+ "members-accepted".
+
+2006-09-25 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-manager.c: Create connection objects only if they
+ are not already created.
+
+ * src/mcd-presence-frame.h, src/mcd-controller.c,
+ src/mcd-connection.c, src/mcd-service.c,
+ src/mcd-signals-marshal.list, src/mcd-presence-frame.c:
+ Defined a new 'status-actual' signal that acts as the accumulated
+ connection signal for all accounts. Shutdown MC if accumulated
+ connection status gets to DISCONNECTED (i.e. all accounts has
+ got to disconnected state). Also when created a new connection,
+ it might fail immidiately and we may not have a chance to capture
+ the status changed signal. Take care of that if the status is
+ disconnected just after creating a connection.
+
+2006-09-25 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (_mcd_channel_set_property),
+ (mcd_channel_new): Only make assertions if the telepathy channel being
+ set is not NULL.
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ Add connection status to debug output.
+
+2006-09-25 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ Rewrote the function using a switch() on the connection status.
+ Calls to dbus_g_proxy_disconnect_signal() have been removed,
+ since the dispose or abort functions should take care of them.
+
+2006-09-25 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ Move the call to mcd_presence_frame_set_account_status() before the
+ call to _mcd_connection_set_presence(), because otherwise the
+ requested presence will not be set successfully.
+
+2006-09-23 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-mission.c, src/mcd-mission.h, src/mcd-connection.c,
+ src/mcd-service.c, src/mcd-operation.c, src/mcd-manager.c,
+ src/mcd-proxy.c, src/mcd-dispatcher.c, src/mcd-master.c,
+ src/mcd-presence-frame.c: Removed bunch of virtual functions for
+ system states, instead used a generic flags that could be
+ set or unset. All system states now use this flags api.
+
+ * src/mcd-connection.c: Abort connection correctly by holding a
+ temporary reference to it (because it is not not know in advance
+ if the object would die during updating of account connection status).
+
+ * src/mcd-operation.c: Disconnect listening to abort signal in
+ dispose.
+
+ * src/mcd-manager.c: Used gtk idle to call on_presence_request_idle()
+ in _mcd_manager_connect() (just like it's been done in
+ on_presence_requested()). The call in _connect() was just a delayed
+ invokation.
+
+2006-09-22 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-channel.c: (_mcd_channel_release_tp_channel):
+ Put some more debug.
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb),
+ (_mcd_connection_release_tp_connection), (_mcd_connection_dispose):
+ Disconnect tp_conn seperately.
+ * src/mcd-manager.c: (mcd_manager_remove_account):
+ Call mcd_mission_abort instead of emiting the signal.
+ * src/mcd-master.c: (_mcd_master_on_account_enabled):
+ Add account to manager first and then presence_frame.
+ * src/mcd-presence-frame.c: (mcd_presence_frame_add_account),
+ (mcd_presence_frame_remove_account): Do not set presence/status of the
+ account yourself on add/remove of account.
+
+2006-09-22 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_set_presence),
+ (_mcd_connection_status_changed_cb):
+ Avoid calling mcd_presence_frame_set_account_status() if
+ the presence-frame is gone.
+
+ * src/mcd-manager.c: (_mcd_manager_disconnect),
+ (mcd_manager_class_init):
+ Abort all connections when getting disconnected.
+
+ * src/mcd-master.c: (_mcd_master_disconnect),
+ (mcd_master_get_account_status),
+ (mcd_master_get_account_connection_details):
+ unref() the accounts returned by rtcom_account_lookup().
+
+ * src/mcd-mission.c: (mcd_mission_class_init):
+ Added "dimmed" and "lit" signals.
+
+2006-09-22 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb):
+ no need to unref DBusConnection.
+
+2006-09-22 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-channel.c: (_mcd_channel_dispose),
+ (mcd_channel_get_members):
+ * src/mcd-connection.c: (_mcd_connection_dispose):
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (on_master_abort),
+ (_mcd_dispatcher_handle_channel_async_cb),
+ (_mcd_dispatcher_start_channel_handler),
+ (_mcd_dispatcher_set_property),
+ (mcd_dispatcher_context_get_channel_object),
+ (mcd_dispatcher_context_get_connection),
+ (mcd_dispatcher_context_get_connection_object):
+ * src/mcd-manager.c: (_mcd_manager_create_connection),
+ (_mcd_manager_create_connections), (_find_connection),
+ (_find_connection_by_path), (on_account_status_changed),
+ (_mcd_manager_set_property), (_mcd_manager_get_property),
+ (mcd_manager_can_handle_account), (mcd_manager_add_account),
+ (mcd_manager_remove_account):
+ * src/mcd-master.c: (_manager_has_account),
+ (_mcd_master_find_manager), (_is_manager_responsible),
+ (_mcd_master_find_potential_manager),
+ (_mcd_master_on_account_enabled),
+ (_mcd_master_on_account_disabled),
+ (_mcd_master_init_account_monitoring), (_get_default_presence),
+ (mcd_master_init), (mcd_master_get_account_for_connection):
+ * src/mcd-mission.c: (on_parent_abort), (_mcd_mission_set_parent),
+ (_mcd_set_property):
+ * src/mcd-presence-frame.c:
+ (_mcd_presence_frame_update_actual_presence),
+ (mcd_presence_frame_set_account_presence),
+ (mcd_presence_frame_set_account_status),
+ (mcd_presence_frame_add_account),
+ (mcd_presence_frame_remove_account):
+ * src/mcd-presence-frame.h:
+ * src/mcd-service.c: (mcd_service_init):
+ - Attempt to add support for setting the account presence on the fly
+ as soon as it get's enabled/disabled.
+ - Fixed reference leaks.
+
+2006-09-22 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-master.h, src/mcd-presence-frame.h,
+ src/mcd-connection.c, src/mcd-service.c,
+ src/mcd-manager.c, src/mcd-dispatcher.c,
+ src/Makefile.am, src/mcd-master.c,
+ src/mcd-presence-frame.c,
+ libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control.h,
+ libmissioncontrol/Makefile.am: Removed deprecated codes.
+
+ * configure.ac: Removed dead code.
+
+2006-09-22 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-debug.h, src/mcd-debug.c,
+ src/mcd-service.c, src/mcd-mission.c, src/mcd-controller.c,
+ src/mcd-mission.h, src/Makefile.am: Added a hierarchy printing
+ debug function. Moved all debug codes to mcd-debug.[ch].
+
+2006-09-22 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-operation.c: Abort children when abort requested on
+ operation.
+
+2006-09-22 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-mission.c: (mcd_mission_ref), (mcd_mission_unref):
+ Add McdMission's reference count to g_debug information.
+
+2006-09-21 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-manager.c: (on_presence_requested),
+ (_mcd_manager_connect), (mcd_manager_class_init):
+ Call on_presence_request_idle() only after the connection has
+ been set up.
+
+2006-09-21 Naba Kumar <naba.kumar@nokia.com>
+
+ * debian/control, debian/mission-control-dev.install,
+ debian/mission-control.install, debian/libmissioncontrol-dev.install,
+ debian/libmissioncontrol.install: Removed no longer used dependencies.
+ Device implementation of mission-control has been moved outside
+ this package.
+
+ * mission-control.pc.in: Added libmissioncontrol-server in LIBS.
+
+ * src/mcd-device-controller.c, src/mcd-main.c, configure.ac,
+ src/mcd-device-controller.h: No longer any device specific code.
+
+ * src/Makefile.am: Disable build for the daemon for now.
+
+ * src/mcd-service.c, src/mcd-service.h: Fixed include file.
+
+ * (removed) mcd-filtering.c, (removed) mcd-filtering.h,
+ mcd-connection.c: Removed dead files and code.
+
+ * (removed) src/mcd-object.c, (added) src/mcd-service.c,
+ (removed) src/mcd-object.h, (added) src/mcd-service.h,
+ src/mcd-device-controller.h, src/Makefile.am: Renamed files
+ to mcd-service.[c,h].
+
+ * src/mcd-object.[ch], mcd-device-controller.[ch],
+ src/mcd-main.c: Renamed class McdObject to more appropriate
+ McdService.
+
+ * src/mcd-device-controller.c: Fixed compile errors.
+
+ * src/Makefile.am, xml/mcd-dbus-services.xml: Generate service
+ header files as mcd-service-gen.h instead of mcd-dbus-services-gen.h.
+
+ * src/mcd-object.c, src/mcd-object.h: Use mcd-service-gen.h
+ for dbus service methods. Register dbus interface to the class in
+ class init and register dbus object in instance init. Use dbus
+ connection object from master instead of creating one by itself.
+
+ src/mcd-connection.c: Use only dbus connection object from master.
+ src/mcd-master.c: Flush dbus connection object before exit.
+
+ * src/mcd-device-controller.c, src/mcd-device-controller.h: Fixed
+ class structure and cleaned up.
+
+2006-09-21 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ When a connection is created, set its presence status according to
+ what is currently requested in the presence frame.
+
+2006-09-20 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dbus-services.c, mcd-object.c: Moved dbus services to
+ McdObject class definition.
+
+ * src/mcd-object.c, src/mcd-object.h, src/mcd-controller.c,
+ src/mcd-controller.h,
+ (new) src/mcd-device-controller.c, src/mcd-main.c
+ (new) src/mcd-device-controller.h, src/Makefile.am,
+ src/mcd-master.c: Separated libmissioncontrol-server library
+ from the main application. Separated device specific logic
+ away from the server library and into application (daemon).
+
+ * src/mcd-init.c, src/mcd-telepathy-handler.c,
+ src/mcd-dsm.c, src/mcd-dsm.h, src/mcd.h,
+ mcd-dus-services.c: Removed dead files.
+
+2006-09-19 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-channel.c: (_mcd_channel_dispose):
+ Set the is_disposed member to TRUE in the dispose() method.
+ * src/mcd-presence-frame.c: (_mcd_presence_frame_dispose),
+ (_mcd_presence_frame_finalize), (mcd_presence_frame_class_init):
+ Move the call to g_hash_table_destroy() from the finalize()
+ method to the dispose() one, since this table holds references to
+ other objects.
+
+2006-09-19 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-chan-handler.c: (_mcd_channel_handler_free),
+ (_mcd_channel_handler_packer):
+ * src/mcd-chan-handler.h:
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb),
+ (_mcd_dispatcher_start_channel_handler),
+ (mcd_dispatcher_context_get_chan_handler):
+ - Rename ChannelHandler to McdChannelHandler.
+ - Implement a getter for the McdChannelHandler object.
+
+2006-09-19 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_new_channel_cb):
+ Fix updating of pending channels' hash table when a new channel is
+ added.
+
+2006-09-12 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * libmissioncontrol/mission-control.c:
+ (_missioncontrol_register_signal_marshallers),
+ (mission_control_init), (mission_control_dispose),
+ (mission_control_class_init), (mission_control_get_type),
+ (mission_control_new), (mission_control_set_presence),
+ (mission_control_get_presence),
+ (mission_control_get_presence_actual),
+ (mission_control_request_channel),
+ (mission_control_request_channel_with_string_handle),
+ (mission_control_connect_all_with_default_presence),
+ (mission_control_get_connection_status),
+ (mission_control_get_online_connections),
+ (mission_control_get_connection),
+ (mission_control_cancel_last_request),
+ (mission_control_get_account_for_connection),
+ (mission_control_get_used_channels_count), (_handle_mcd_errors),
+ (set_presence_async_cb), (request_channel_async_cb),
+ (request_channel_with_string_handle_async_cb),
+ (connect_all_with_default_presence_async_cb), (check_for_accounts),
+ (check_mc_running), (cancel_last_request_async_cb):
+ Merge changes from old mc.
+ * src/mcd-dispatcher.c: (mcd_dispatcher_register_filter_chain),
+ (_mcd_dispatcher_enter_state_machine):
+ Add some more info to the debug output.
+
+2006-09-08 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-channel.c: Removed construct only flags for the
+ properties.
+
+ * src/mcd-main.c: Shutdown 3rd party services correctly.
+
+ * src/mcd-mission.c, src/mcd-operation.c: Release reference to
+ parent mission on its abort signal.
+
+2006-09-08 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dispatcher.c: (on_object_abort),
+ (_mcd_dispatcher_set_property):
+ Watch for abort signal and unref the object on abort.
+ * src/mcd-master.c: (_mcd_master_dispose), (mcd_master_class_init):
+ Master should also over-ride the dispose method to unref all the
+ member objects.
+
+2006-09-08 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-manager.c: Nuke stale telepathy connections before
+ mission control takes over the job.
+
+ * src/mcd-connection.cm, src/mcd-channel.c, src/mcd-channel.h:
+ Get rid of hacky pending request sturct and instead use Channel
+ object themselfs as pending channels. Implemented get/set
+ channel status.
+
+ * xml/mcd-dbus-services.xml: Introduced GetUsedChannelsCount
+ method again.
+
+ * src/mcd-dbus-services.c: Reordered dbus method implementations
+ and defined them as static functions.
+
+2006-09-08 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-main.c: (_shutdown_3rd_party_services),
+ (_raise_3rd_party_services), (main):
+ Raise 3rd-party services on start-up and shut them down on abort.
+ * src/mcd-master.c: (_mcd_master_get_property),
+ (mcd_master_class_init):
+ Add 'dbus-connection' property to McdMaster.
+
+2006-09-08 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-mission.c: (mcd_mission_class_init):
+ Register McdMode as a GType rather than a GEnum.
+
+2006-09-08 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_enter_state_machine),
+ (mcd_dispatcher_context_process):
+ Rename mcd_process_sm to mcd_dispatcher_context_process. Remove
+ mcd_cancel_sm
+
+2006-09-08 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c: Listen and respond to channel dispached and
+ friends signals.
+
+ * src/mcd-connection.c: Removed dead code and notify channel
+ abort if telepathy connection is disconnected.
+
+ * src/mcd-channel.c, src/mcd-channel.h: Defined channel status enum
+ and a notification signal for it.
+
+ * src/mcd-signals-marshal.list, src/mcd-dispatcher.c,
+ src/mcd-dispatcher.h: Implemented
+ channel-added, channel-removed, dispached, dispatch-failed signals.
+ and emit dispatch failed error messages.
+
+ * configure.ac, src/Makefile.am, src/mcd-mission.c: Generate enum
+ types dynamically.
+
+ * src/mcd-master.c: Make dispatcher a property of master.
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb),
+ (_mcd_dispatcher_start_channel_handler),
+ (_mcd_dispatcher_drop_channel_handler),
+ (_mcd_dispatcher_leave_state_machine), (on_channel_abort_context),
+ (_mcd_dispatcher_enter_state_machine), (mcd_process_sm),
+ (mcd_dispatcher_context_free),
+ (mcd_dispatcher_context_get_channel_object),
+ (mcd_dispatcher_context_get_dispatcher),
+ (mcd_dispatcher_context_get_connection_object),
+ (mcd_dispatcher_context_get_channel),
+ (mcd_dispatcher_context_get_data),
+ (mcd_dispatcher_context_get_connection),
+ (mcd_dispatcher_context_get_members),
+ (mcd_dispatcher_context_set_abort_fn),
+ (mcd_dispatcher_context_set_data):
+ Rename all sm_context_t to McdDispatcherContext and also the functions
+ related to this sturcture.
+
+2006-09-07 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c: Cancel shutdown if a new presence was
+ requested which is not offline.
+
+ * src/mcd-mission.c, src/mcd-mission.h: Use better ref/unref
+ wrapper.
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c:
+ Remove wrapper functions for lock/unlock.
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb),
+ (_mcd_dispatcher_start_channel_handler), (mcdf_ctx_get_connection):
+ Removed some more wrapper functions.
+
+2006-09-07 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c, src/mcd-mission.c, src/mcd-connection.c,
+ src/mcd-channel.c, src/mcd-main.c, src/mcd-dispatcher.c: Fixed 'abort'
+ signals and object life cycles. Exit mission-control on shutdown
+ timeout. Fixed state machine context handling.
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c:
+ Removed the device state related wrapper functions.
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_handle_channel_async_cb),
+ (_mcd_dispatcher_start_channel_handler), (mcdf_ctx_get_channel):
+ Removed the channel-related wrapper functions.
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-dispatcher-context.h:
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_enter_state_machine),
+ (mcdf_ctx_get_display_state): Update device_state API to use booleans
+ instead of enums.
+ * src/mcd-mission.c: (mcd_mission_class_init): register mode by its
+ GType rather than as enum.
+
+2006-09-07 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-controller.c, src/mcd-mission.h,
+ src/mcd-controller.h, src/mcd-operation.c
+ src/mcd-main.c, src/mcd-master.c: Fixed mission-control shutdown
+ and object abort signals.
+
+ * src/mcd-dispatcher.c: Moved context creation in enter state
+ machine.
+
+ * src/mcd-object.c, xml/mcd-dbus-services.xml,
+ src/mcd-signals-marshal.list, src/mcd-dbus-services.c:
+ Fixed method parameters.
+
+ * src/mcd-connection.c, src/mcd-channel.c, src/mcd-manager.c,
+ src/mcd-dispatcher.c, src/mcd-master.c,
+ src/mcd-operation.c, src/mcd-operation.h: Removed get_children()
+ method because there is similar get_missions() method and fixed
+ several memory corruptions. Fixed filters chains initialization.
+ Disabled filters for now (until the filters are fixed).
+
+2006-09-07 Alberto Mardegan <alberto.mardegan@nokia.com>
+
+ * src/mcd-mission.c: (mcd_mode_get_type), (_mcd_mission_set_mode),
+ (mcd_mission_class_init): Register the McdMode enum.
+
+2006-09-06 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-connection.c, src/mcd-dispatcher.c: Pass handle and
+ handle_type correctly. Fixed channel handlers launching.
+
+ * src/mcd-connection.c, src/mcd-channel.c,
+ src/mcd-dispatcher.c, src/mcd-master.c: Fixed dispatcher
+ propagation and channel properties.
+
+ * src/mcd-dispatcher-context.h, src/mcd-dispatcher.c:
+ Implement the lock/unlock function for the filters.
+ Port some more functions from the old mission-control.
+
+ * src/Makefile.am:
+ Also distribute mcd-dispatcher-context.h
+
+2006-09-06 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dispatcher.[c,h], src/mcd-dispatcher-context.h:
+ separated plugin context API from main dispatcher API.
+
+ * src/mcd-connection.c, src/mcd-connection.h,
+ src/mcd-manager.c, src/mcd-manager.h,
+ src/mcd-dispatcher.c, src/mcd-master.c,
+ src/mcd-dispatcher.h: Passed down dispatcher and dispatch
+ new channels.
+
+2006-09-05 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-master.h, src/mcd-object.c, src/mcd-manager.c,
+ src/mcd-dbus-services.c, src/mcd-manager.h,
+ src/mcd-master.c: Implemented new method
+ mcd_get_account_for_connection() properly.
+
+ * src/mcd-object.c: Implemented mission control error quark.
+
+ * src/mcd-dbus-services.c: Implemented new method
+ mcd_get_account_for_connection()
+
+ * libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control.h,
+ libmissioncontrol/mission-control-signals-marshal.list: Restored
+ libmissioncontrol from old MC.
+
+ * src/mcd-dispatcher.c, src/mcd-dispatcher.h: Added get/set
+ dispatcher methods in context.
+
+ * src/mcd-dispatcher.h: Fixed build error.
+
+ * src/mcd-chan-handler.c: Added missing file.
+
+ * src/mcd-master.h, src/mcd-chan-handler.h,
+ src/mcd-dbus-services.c, src/mcd-dispatcher.c,
+ src/Makefile.am, src/mcd-master.c, src/mcd-dispatcher.h:
+ Implemented missing pieces in dispatcher.
+
+ * src/mcd-dbus-services.c: Fixed build error due to
+ change in function name.
+
+2006-09-04 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-channel.c: Implemented mcd_channel_get_members().
+
+ * src/mcd-master.h, src/mcd-connection.c,
+ src/mcd-connection.h, src/mcd-channel.c,
+ src/mcd-manager.c, src/mcd-channel.h,
+ src/mcd-dbus-services.c, src/mcd-manager.h,
+ src/mcd-master.c: Implemented channel request stack.
+
+2006-09-03 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-controller.c, rc/mcd-channel.c,
+ mrc/mcd-channel.h, src/mcd-dispatcher.c, src/mcd-dispatcher.h:
+ Ported filtering codes.
+
+2006-08-30 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/Makefile.am, mission-control.pc.in: Install header files and
+ fixed include path.
+
+ * src/mcd-connection.c, src/mcd-channel.c, src/mcd-channel.h: Added
+ extra channel parameters.
+
+2006-08-30 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_free_presence_info),
+ (_find_handle), (_mcd_connection_map_status_to_presences),
+ (_mcd_connection_presence_update_cb),
+ (_mcd_connection_store_tp_self_handle),
+ (_mcd_connection_get_tp_status_cb),
+ (_mcd_connection_set_fallback_presences),
+ (_mcd_connection_presence_enable), (on_presence_requested),
+ (_foreach_channel_remove), (_mcd_connection_status_changed_cb),
+ (_mcd_connection_setup), (_mcd_connection_dispose),
+ (_mcd_connection_set_property),
+ (mcd_connection_get_telepathy_details):
+ * src/mcd-connection.h:
+ * src/mcd-controller.c: (_mcd_controller_device_mode_cb),
+ (_mcd_controller_device_state_filter_func),
+ (_mcd_mode_to_mce_mode), (_mcd_controller_set_mode):
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_load_filters),
+ (_mcd_dispatcher_unload_filters), (mcd_dispatcher_init),
+ (mcd_dispatcher_new), (channel_usage_counter),
+ (mcdf_get_channel_type_usage), (on_channel_members_changed),
+ (mcd_get_filter_chain), (mcd_register_filter_chain),
+ (mcd_unregister_filter_chain),
+ (mcd_dispatcher_remove_channel_watch), (get_local_pending_cb),
+ (mcd_dispatcher_add_channel_watch), (on_channel_closed),
+ (dispose_channel_request), (dispose_state_machine_data),
+ (mcd_cancel_sm), (enter_state_machine),
+ (mcdf_ctx_get_dbus_connection), (mcdf_ctx_get_account),
+ (mcdf_ctx_get_profile), (mcdf_ctx_set_data):
+ * src/mcd-dispatcher.h:
+ * src/mcd-filtering.c: (mcdf_ctx_get_channel_object),
+ (mcdf_ctx_get_request_chan_type_quark),
+ (mcdf_ctx_get_request_chan_type),
+ (mcdf_ctx_get_request_conninfo_proxy),
+ (mcdf_ctx_get_request_conninfo_account_name),
+ (mcdf_ctx_get_request_conninfo_self_handle),
+ (mcdf_ctx_get_request_obj_path),
+ (mcdf_ctx_get_request_handle_type), (mcdf_ctx_get_request_handle),
+ (mcdf_ctx_get_book), (mcdf_ctx_get_dbus_connection),
+ (mcdf_ctx_get_display_state), (mcdf_ctx_get_battery_state),
+ (mcdf_ctx_get_keylock_state), (mcdf_ctx_get_lowmem_state),
+ (mcdf_ctx_get_data), (mcdf_ctx_get_flags),
+ (mcdf_ctx_get_account), (mcdf_ctx_get_profile),
+ (_contact_handles_to_strings), (mcdf_ctx_get_members),
+ (mcdf_ctx_set_abort_fn), (mcdf_ctx_set_data),
+ (dispose_channel_request), (dispose_state_machine_data),
+ (start_channel_handler), (drop_channel_handler), (mcd_process_sm),
+ (mcd_cancel_sm), (enter_state_machine),
+ (mcd_async_request_chan_callback), (mcd_get_filter_chain),
+ (mcd_register_filter_chain), (mcd_unregister_filter_chain),
+ (on_channel_closed), (on_channel_memberschanged),
+ (get_local_pending_cb), (channel_usage_counter),
+ (mcdf_get_channel_type_usage), (mcdf_set_tklock_unlocked),
+ (remove_channel_watch), (add_channel_watch), (set_voip_mode),
+ (set_tklock), (channelhandler_destroy_cb),
+ (handle_channel_async_cb):
+ * src/mcd-filtering.h:
+ * src/mcd-manager.c: (_mcd_manager_create_connections),
+ (_find_connection), (on_account_status_changed),
+ (on_presence_requested_idle), (_mcd_manager_set_property),
+ (mcd_manager_new), (mcd_manager_get_account_connection):
+ * src/mcd-master.c: (_mcd_master_init_managers),
+ (_get_default_presence), (_is_manager_responsible),
+ (_mcd_master_find_manager), (_mcd_master_sleep),
+ (mcd_master_get_account_status),
+ (mcd_master_get_online_connection_names),
+ (mcd_master_get_account_connection_details):
+ * src/mcd-master.h:
+ * src/mcd-mission.c: (_mcd_mission_dispose),
+ (_mcd_mission_finalize), (mcd_mission_class_init):
+ * src/mcd-mission.h:
+ * src/mcd-object.c: (_on_account_status_changed),
+ (_on_account_presence_changed), (_on_presence_requested),
+ (_on_presence_actual), (mcd_object_get):
+ * src/mcd-operation.c: (_mcd_operation_dispose),
+ (_mcd_operation_remove_mission), (mcd_operation_get_children):
+ * src/mcd-operation.h:
+ * src/mcd-presence-frame.c: (_presence_to_status),
+ (_mcd_presence_frame_request_presence),
+ (mcd_presence_frame_request_presence),
+ (mcd_presence_frame_cancel_last_request),
+ (_mcd_presence_frame_update_actual_presences),
+ (_mcd_presence_frame_update_actual_presence),
+ (mcd_presence_frame_set_account_presence),
+ (mcd_presence_frame_set_account_status):
+ * src/mcd-presence-frame.h:
+ * src/mcd-proxy.c: (_mcd_proxy_abort),
+ (_mcd_proxy_connect_signals), (_mcd_proxy_disconnect_signals),
+ (_mcd_proxy_dispose), (mcd_proxy_new):
+ * src/mcd-proxy.h: Fix indentation.
+
+2006-08-30 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-filtering.[c,h]: Moved codes from old MC.
+
+2006-08-30 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/Makefile.am: Treat warnings as errors.
+ * src/mcd-controller.c: (_mcd_controller_set_mode): remove unused
+ varriable.
+ * src/mcd-dispatcher.c: (on_channel_members_changed),
+ (get_local_pending_cb), (mcd_dispatcher_add_channel_watch),
+ (mcdf_ctx_set_abort_fn):
+ * src/mcd-dispatcher.h:
+ * src/mcd-manager.c: (mcd_manager_init):
+ * src/mcd-mission.c: (mcd_mission_get_mode): Small fixes to make
+ mc built with the latest changes.
+
+2006-08-30 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-mission.c: Fixed compiler warnings.
+
+2006-08-29 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * libmissioncontrol/mission-control.c:
+ (mission_control_get_presence),
+ (mission_control_get_presence_actual):
+ * src/Makefile.am:
+ * src/mcd-chan-handler.h:
+ * src/mcd-connection.c: (_mcd_connection_status_changed_cb):
+ * src/mcd-controller.c: (_mcd_controller_device_mode_cb),
+ (_mcd_controller_device_state_filter_func),
+ (_mcd_mode_to_mce_mode), (_mcd_controller_set_mode),
+ (mcd_controller_class_init):
+ * src/mcd-dispatcher.c: (_mcd_dispatcher_send),
+ (_mcd_dispatcher_load_filters), (_mcd_dispatcher_unload_filters),
+ (_mcd_dispatcher_set_property), (_mcd_dispatcher_get_property),
+ (_mcd_dispatcher_dispose), (mcd_dispatcher_class_init),
+ (mcd_dispatcher_init), (mcd_dispatcher_new),
+ (channel_usage_counter), (mcdf_get_channel_type_usage),
+ (on_channel_memberschanged), (mcd_get_filter_chain),
+ (mcd_register_filter_chain), (mcd_unregister_filter_chain),
+ (mcd_dispatcher_remove_channel_watch),
+ (mcd_dispatcher_add_channel_watch), (on_channel_closed),
+ (start_channel_handler), (drop_channel_handler), (mcd_process_sm),
+ (dispose_channel_request), (dispose_state_machine_data),
+ (mcd_cancel_sm), (enter_state_machine),
+ (mcdf_ctx_get_channel_object),
+ (mcdf_ctx_get_request_chan_type_quark),
+ (mcdf_ctx_get_request_chan_type), (mcdf_ctx_get_request_obj_path),
+ (mcdf_ctx_get_request_handle_type), (mcdf_ctx_get_request_handle),
+ (mcdf_ctx_get_book), (mcdf_ctx_get_dbus_connection),
+ (mcdf_ctx_get_display_state), (mcdf_ctx_get_battery_state),
+ (mcdf_ctx_get_keylock_state), (mcdf_ctx_get_data),
+ (mcdf_ctx_get_account), (mcdf_ctx_get_profile),
+ (mcdf_ctx_get_members), (mcdf_ctx_set_abort_fn),
+ (mcdf_ctx_set_data):
+ * src/mcd-dispatcher.h:
+ * src/mcd-filtering.c:
+ (mcdf_ctx_get_data), (mcdf_ctx_get_account),
+ (mcdf_ctx_get_profile), (mcd_get_filter_chain),
+ (mcd_register_filter_chain), (mcd_unregister_filter_chain):
+ * src/mcd-filtering.h:
+ * src/mcd-manager.c: (on_account_status_changed),
+ (mcd_manager_class_init), (mcd_manager_init), (mcd_manager_new),
+ (mcd_manager_get_account_connection):
+ * src/mcd-manager.h:
+ * src/mcd-master.c: (_mcd_master_init_managers),
+ (_mcd_master_find_manager), (mcd_master_init),
+ (mcd_master_get_account_connection_details):
+ * src/mcd-mission.c: (_mcd_mission_set_mode),
+ (_mcd_mission_get_mode), (_mcd_set_property), (_mcd_get_property),
+ (mcd_mission_class_init), (mcd_mission_set_mode),
+ (mcd_mission_get_mode):
+ * src/mcd-mission.h:
+ * src/mcd-object.c:
+ * src/mcd-operation.c:
+ * src/mcd-operation.h:
+ Trying to port dispatcher with working code from the old mc.
+
+2006-08-26 Naba Kumar <naba.kumar@nokia.com>
+
+ * (new) src/mcd-proxy.[c,h], src/Makefile.am: Implemented
+ proxy class.
+
+2006-08-21 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-presence-frame.c: (mcd_presence_free): No need to check for
+ NULL before calling g_free() on a pointer.
+
+2006-08-18 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-manager.c: Removed an unneeded function:
+ mcd_manager_get_account_status.
+
+2006-08-18 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dbus-services.c: (mcd_cancel_last_request):
+ * src/mcd-master.c: (mcd_master_cancel_last_request):
+ * src/mcd-master.h:
+ * src/mcd-presence-frame.c: (mcd_presence_new),
+ (mcd_presence_free), (mcd_presence_copy),
+ (_mcd_presence_frame_finalize), (mcd_presence_frame_init),
+ (_mcd_presence_frame_request_presence),
+ (mcd_presence_frame_request_presence),
+ (mcd_presence_frame_cancel_last_request):
+ * src/mcd-presence-frame.h:
+ Implement CancelLastRequest.
+
+2006-08-18 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (mcd_connection_get_telepathy_details):
+ * src/mcd-connection.h:
+ * src/mcd-dbus-services.c: (mcd_get_connection):
+ * src/mcd-manager.c: (_find_connection),
+ (mcd_manager_get_account_connection):
+ * src/mcd-manager.h:
+ * src/mcd-master.c: (_is_manager_responsible),
+ (_mcd_master_find_manager),
+ (mcd_master_get_online_connection_names),
+ (mcd_master_get_account_connection_details):
+ * src/mcd-master.h:
+ Implement GetConnection.
+
+2006-08-17 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dbus-services.c: (mcd_get_online_connections):
+ * src/mcd-master.c: (mcd_master_get_online_connection_names):
+ * src/mcd-master.h: Implement GetOnlineConnections.
+
+2006-08-17 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dbus-services.c: (mcd_get_connection_status):
+ * src/mcd-manager.c: (on_presence_requested_idle),
+ (mcd_manager_get_account_status):
+ * src/mcd-master.c: (mcd_master_get_account_status):
+ * src/mcd-master.h: Implement GetConnectionStatus.
+ * src/mcd-presence-frame.c: (_presence_to_status),
+ (_mcd_presence_frame_update_actual_presence): Refactor: Put the
+ presence to status translation into a static inline function.
+
+2006-08-17 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dbus-services.c: (mcd_connect_all_with_default_presence),
+ (mcd_request_channel), (mcd_request_channel_with_string_handle):
+ * src/mcd-master.c: (_get_default_presence),
+ (mcd_master_set_default_presence):
+ * src/mcd-master.h:
+ Implement ConnectAllWithDefaultPresence.
+
+2006-08-16 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-dbus-services.c: (mcd_get_presence),
+ (mcd_get_presence_actual):
+ * src/mcd-master.c: (mcd_master_get_actual_presence),
+ (mcd_master_get_requested_presence):
+ * src/mcd-master.h: Implement GetPresence and GetPresenceActual.
+
+2006-08-16 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-mission.c, src/mcd-operation.c, src/mcd-controller,
+ src/mcd-master.c, src/mcd-object: Added some class documents.
+
+2006-08-16 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-manager.c: (on_presence_requested_idle): Corrected the logic
+ for deciding wether to create the connection manager and connections.
+
+2006-08-16 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_set_property): One more line
+ break makes code a bit clearer.
+ * src/mcd-manager.c: (on_presence_requested_idle): Only create TP
+ connection manager and connections if they are not already created.
+ * src/mcd-object.c: (_on_account_presence_changed),
+ (mcd_object_get): Handle presence-changed and emit the appropriate
+ signal on the dbus.
+ * src/mcd-presence-frame.c: (mcd_presence_frame_class_init),
+ (mcd_presence_frame_set_account_presence): rename presence-set signal to
+ pressence-changed.
+
+2006-08-15 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-master.c: (_mcd_master_sleep): Only set presence to away
+ automatically if the current presence is AVAILABLE.
+
+2006-08-15 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-controller.c: (_mcd_controller_on_sleep_timeout),
+ (_mcd_controller_inactivity_cb): Introduce a timeout function for
+ auto-away
+ * src/mcd-master.c: (_mcd_master_sleep), (_mcd_master_wakeup),
+ (mcd_master_class_init): Override sleep/wakeup to implement auto-away.
+ * src/mcd-presence-frame.c:
+ (mcd_presence_frame_get_actual_presence),
+ (mcd_presence_frame_get_actual_presence_message):
+ * src/mcd-presence-frame.h: Add API to support querying actual presence.
+
+2006-08-15 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_presence_enable):
+ BUGFIX: assuming wrong type of user_data in a callback, which
+ made mc segfault when setting the presence to away.
+
+2006-08-15 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (on_presence_requested): A small indentation
+ fix.
+ * src/mcd-presence-frame.c: (_mcd_presence_frame_finalize),
+ (mcd_presence_frame_set_account_status): save the previous status of
+ accounts before updating it and call
+ _presence_frame_set_account_presence() only when needed.
+
+2006-08-14 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-presence-frame.c: (_mcd_presence_frame_finalize),
+ (mcd_presence_frame_init),
+ (mcd_presence_frame_get_requested_presence),
+ (_mcd_presence_frame_update_actual_presence),
+ (mcd_presence_frame_get_account_presence),
+ (mcd_presence_frame_get_account_status),
+ (mcd_presence_frame_get_account_status_reason),
+ (mcd_presence_frame_set_accounts): Keep track of actual presence
+ seperately then the requested presence. assume UNSET to be the
+ lowest presence level rather than OFFLINE.
+
+2006-08-14 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_set_property): Use
+ connect_after instead of connect so that the signal handler is called
+ after all other signal handlers.
+ * src/mcd-manager.c: (on_presence_requested_idle),
+ (on_presence_requested): set the presence in an idle handler.
+
+2006-08-11 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (mcd_connection_class_init): Fixed a small typo in
+ naba's last commit.
+
+2006-08-11 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-connection.c: (_mcd_connection_setup): Emit a dbus signal
+ on connecting the accounts
+ * src/mcd-object.c: (_on_presence_actual), (mcd_object_get): Rename
+ presence-settled to presence-actual.
+ * src/mcd-presence-frame.c: (mcd_presence_frame_class_init),
+ (_mcd_presence_frame_update_actual_presences),
+ (_mcd_presence_frame_update_actual_presence),
+ (mcd_presence_frame_set_account_presence),
+ (mcd_presence_frame_set_account_status): Rename
+ presence-settled to presence-actual and try to emit presence-actual
+ signal when it's time to do so.
+ * src/mcd-presence-frame.h: Rename
+ presence-settled to presence-actual.
+
+2006-08-10 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-connection.c: Fixed property param spec.
+
+ * src/mcd-connection.c: Implemented presence status changes
+ from telepathy connection.
+
+ * src/mcd-connection.c: Backported new changes from old mission
+ control.
+
+2006-08-09 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/mcd-object.c: (_on_presence_settled), (mcd_object_get):
+ Emit PresenceStatusActual signal when/if received from the
+ presence-frame
+
+2006-08-09 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * ChangeLog: Starting to maintain a ChangeLog from now on.
+
+ * src/mcd-master.h, src/mcd-presence-frame.h, src/mcd-object.c
+ src/mcd-connection.c, src/mcd.h, src/mcd-manager.c, src/mcd-master.c
+ src/mcd-presence-frame.c: Converting from
+ TelepathyConnectionPresenceType to McPresence
+
+ * libmissioncontrol/mission-control.[ch]: Moved code from old
+ missioncontrol.
+
+2006-08-09 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: emit the AccountStatusChanged? signal on the dbus so
+ that presence
+
+2006-08-09 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: applet can update itself.
+
+2006-08-08 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: You can go now go online, then offline and then
+ again online and so on without causing a segfault. :)
+
+2006-08-03 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: Use the dbus bus that started us rather than the
+ session bus.
+
+2006-08-03 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ Figure-out and save the new state on presence change.
+
+2006-07-27 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ Renamed mcd_master_set_presence() to mcd_master_request_presence()
+
+2006-07-27 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ Renamed the object varriable according to the new API (athough the code
+ is commented out atm)
+
+2006-07-27 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ Renamed the MCObject structures to McdObject?
+
+2006-07-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ Setting the indentation according to the gnu coding style
+
+2006-07-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ g_object_new expects a NULL in the end (bugfix)
+
+2006-07-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ Connecting the chain of SetPresence?
+
+2006-07-26 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c:
+ DBUS_API_SUBJECT_TO_CHANGE declaration is enough in one place
+ (Makefile.am)
+
+2006-07-25 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: Corrected the verion in debian/changelog
+
+2006-07-25 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: Imported signals to mcd-object from the old version
+
+2006-07-25 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: Moved some more code from the old mission-control
+
+2006-07-25 Zeeshan Ali <zeeshan.ali@nokia.com>
+
+ * src/*.h, src/*.c: Updated the version string in configure.ac and debian files
+
+
+2006-06-12 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-presence-frame.h, src/mcd-connection.c
+ src/mcd-connection.h, src/mcd-channel.c
+ src/mcd-manager.c, src/mcd-channel.h
+ src/mcd-signals-marshal.list, src/mcd-dispatcher.c
+ src/Makefile.am, src/mcd-dispatcher.h
+ src/mcd-presence-frame.c: New implementation of channel class. Futher
+ implementation of connection and presence-frame classes. Initial
+ implementation of dispatcher class.
+
+2006-06-02 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-connection.c, src/mcd-operation.c, src/mcd-master.h,
+ src/mcd-presence-frame.h, src/mcd-connection.h,
+ src/mcd-operation.h, src/mcd-manager.c,
+ src/mcd-signals-marshal.list, src/mcd-manager.h,
+ src/mcd-mission.c, src/mcd-controller.c,
+ src/mcd-mission.h, src/Makefile.am,
+ src/mcd-controller.h, src/mcd-master.c,
+ src/mcd-presence-frame.c: Fixed all classess to build. Partial
+ implementation of all classes.
+
+2006-06-01 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-connection.c, src/mcd-master.h, src/mcd-presence-frame.h,
+ src/mcd-connection.h, src/mcd-manager.c, src/mcd-manager.h,
+ src/mcd-controller.c, src/Makefile.am, src/mcd-master.c,
+ src/mcd-presence-frame.c: Created master, manager
+ and presence frame classes and initial structure.
+
+2006-06-01 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-mission.[c,h], src/mcd-operation.[c,h],
+ src/mcd-controller.[c,h], src/mcd-connection.[c,h], src/Makefile.am:
+ Added initial mission control structure.
+
+2006-05-26 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-init.c, src/mcd-object.c, src/mcd-telepathy-handler.c,
+ src/mcd-object.h, src/mcd-dbus-services.c, src/mcd-filtering.c:
+ Cleanups.
+
+ * src/mcd-dbus-services.c: Refactored common code into
+ _mcd_get_default_presence().
+
+ * src/mcd-dbus-services.c: Refactored common code into
+ _mcd_request_channel().
+
+ * src/mcd-object.c, src/mcd-telepathy-handler.c, src/mcd-object.h:
+ Made mcd_free_presence_info() easier to use.
+
+ * src/mcd-dbus-services.c: Made mcd_cancel_last_request() use
+ _mcd_set_presence().
+
+ * src/mcd-object.c, src/mcd-telepathy-handler.c:
+ _mcd_status_changed_handler() duplicated a lot of code from
+ mcd_set_account_presence().
+
+2006-05-24 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control.h, src/mcd.h,
+ src/mcd-filtering.c(mcd_async_request_chan_callback): Added
+ MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR.
+
+ * src/mcd-filtering.c, src/mcd-object.c,
+ src/mcd-telepathy-handler.c: Minor cleanups.
+
+ * src/mcd-object.c: Don't try to connect the same account more
+ than once. g_hash_table_insert() will call the key_destroy_func
+ on the key if it is already present. This corrupted the object
+ path that was being used as the key.
+
+ * src/mcd-object.c, src/mcd-telepathy-handler.c,
+ src/mcd-object.h, src/mcd-dbus-services.c, src/mcd-filtering.c,
+ xml/mcd-dbus-services.xml, libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control.h: Added presence-status-actual
+ signal which reflects the combined status of out accounts.
+ presence-status-requested was fixed to be emitted when a presence
+ is actually requested.
+
+2006-05-23 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c: Don't clear exit_after_last_channel flag when
+ mcd_connect_all_with_default_presence() is called.
+ Partial fix for bug #27122.
+
+ * src/mcd-init.c: Re-connect all accounts even when connectivity
+ is already connected. Fixes bug #30344.
+
+2006-05-19 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c: Set new connection status to CONNECTING.
+ Fixes bug #29265.
+
+2006-05-19 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dbus-services.c, src/mcd-dsm.c, src/mcd-filtering.c,
+ src/mcd-init.c, src/mcd-object.c, src/mcd-telepathy-handler.c,
+ src/mcd-object.h: Andrei's changes to .manager file reading and
+ minor refactoring + debugging output additions.
+
+2006-05-17 Naba Kumar <naba.kumar@nokia.com>
+ * src/mcd-object.c: Don't hog the CPU and prevent gabble from
+ doing real work.
+
+2006-05-16 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dbus-services.c, xml/mcd-dbus-services.xml,
+ libmissioncontrol/mission-control.[c|h]: Added
+ GetUsedChannelsCount DBUS method with libmissioncontrol
+ bindings to query for ongoing VoIP calls etc. This fixes bug
+ #29651.
+
+2006-05-12 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-filtering.c (start_channel_handler): A few mcd-error
+ signal emits were missing when we had trouble handling the
+ channel. The emits should fix bug #26504.
+
+2006-05-12 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.[c|h], src/mcd-telepathy-handler.c:
+ Reverted _mcd_connection_destroyed_cb removal from yesterday
+ since apparently both this and the recent libtelepathy addition
+ are needed by someone.
+
+2006-05-12 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c: Connection status is now also updated when
+ starting to connect an account. This fixes bug #29265.
+
+ * src/mcd-object.c, src/mcd-signals-marshal.list,
+ xml/mcd-dbus-services.xml, libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control-signals-marshal.list:
+ Added PresenceStatusRequested signal which is emitted whenever a
+ presence change is requested. Emitting can happen due to a request
+ from application, auto-away etc.
+
+2006-05-11 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.[c|h], src/mcd-telepathy-handler.c:
+ Due to recent changes in libtelepathy, mission control is no
+ longer responsible for detecting destroyed connections. Thus,
+ _mcd_connection_destroyed_cb and the associated helper struct
+ destroy_signal_data have been removed as obsolete. Part of
+ fix for bug #28543.
+
+2006-05-09 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c, src/mcd-telepathy-handler.c,
+ src/mcd-signals-marshal.list, xml/mcd-dbus-services.xml,
+ libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control-signals-marshal.list: Backed off
+ the AccountStatusChanged signal modifications done by Tuomas, as
+ we've been requested to do this differently.
+
+ * src/mcd-dsm.c (_close_channel): Mission Control attempted to
+ close chanels with wrong type of pointer when shutdown_ind signal
+ has been received, effectively causing a crash. Now channels are
+ closed properly.
+
+ * src/mcd-filtering.[c|h] (add_channel_watch),
+ (remove_channel_watch): Mission Control will have to monitor
+ MembersChanged signals for VOIP calls in order to know whether the
+ T&K lock needs to be be locked when the call ends. The locking
+ functionality has also been added to MC. MC also provides a method
+ available for filters to indicate whether filters opened the T&K
+ lock.
+
+ * src/mcd-object.[c|h]: A flag has been added to Mission Control
+ for keeping track of T&K unlock operations done by the
+ filters. It's needed to know whether we need to lock T&K again
+ when call ends.
+
+ * src/mcd-init.c (_mcd_setup_device_state_monitoring): Mission
+ Control will request information about the T&K lock status on
+ startup, otherwise we might not know the lock status during the
+ first VOIP call.
+
+2006-05-08 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.[c|h], src/mcd-dbus-services.c,
+ src/mcd-filtering.c: Presence and connectivity are set offline
+ after the last channel closes in case the channel was initiated
+ from those conditions. This fixes bug #27122.
+
+ * src/mcd-object.c, src/mcd-telepathy-handler.c,
+ src/mcd-signals-marshal.list, xml/mcd-dbus-services.xml,
+ libmissioncontrol/mission-control.c,
+ libmissioncontrol/mission-control-signals-marshal.list:
+ AccountStatusChanged signal API changed. Added last requested
+ presence as the signal's second parameter.
+
+ * src/mcd-dbus-services.c: Connectivity is now handled also in
+ ConnectAllWithDefaultPresence method. This fixes bug #26797.
+
+2006-05-05 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dbus-services.c: Cancellation for the pending MC
+ shutdown has been added to situations where it makes sense.
+
+ * src/mcd-init.c (_mcd_iap_cb): When we've been disconnected in an
+ uncontrollable manner, set presence to offline to match reality.
+
+ * src/mcd-dsm.c (_mcd_state_filter_func): The fix for the T&K lock
+ tracking was still not quite right. Corrected a flawed comparison.
+
+ * src/mcd-init.c: Emit an error signal to indicate when we've lost
+ network connectivity in an uncontrolled manner.
+
+2006-05-04 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-init.c (_mcd_inactivity_cb): Fix the autoaway state
+ book-keeping to complete the bug #23758 fix.
+
+ * src/mcd-object.c (mcd_set_presence_autoaway): Do not touch the
+ away message string when going to autoaway.
+
+2006-05-03 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dbus-services.c: Added implementation of the presence
+ revert operation when a request is cancelled.
+
+ * src/mcd-object.[c|h]: Added support for storing the previous
+ presence data when doing a request, so that we can 'cancel' the
+ request.
+
+ * src/mcd.h: MC_NETWORK_ERROR has been added to supported error
+ signals.
+
+ * libmissioncontrol/mission-control.c (_handle_mcd_errors):
+ Support emission of 'generic' errors that are not directly caused
+ by the request performed by the current application. They will
+ have PID parameter value 0. Added method
+ mission_control_cancel_last_request() that can be used to cancel
+ the last method call (currently only really supports the
+ mission_control_request_channel_with_string_handle() cancellation).
+
+ * src/mcd-object.c (_mcd_connect_account_from_hash): Emit
+ MC_NETWORK_ERROR if creation of a connection failed.
+
+ * libmissioncontrol/mission-control.[c|h]: Added the
+ mission_control_connect_all_with_default_presence() method to the
+ API to connect all accounts with default presence when we're not
+ yet offline. MC_NETWORK_ERROR has been added to error signals.
+
+ * src/mcd-dbus-services.c (mcd_connect_all_with_default_presence):
+ Added a handler for the ConnectAllWithDefaultPresence D-BUS
+ method. It will connect all accounts with the default presence
+ value from GConf if we're not online yet.
+
+ * xml/mcd-dbus-services.xml: Added the definition of the new
+ method ConnectAllWithDefaultPresence. Added CancelLastRequest
+ method definition.
+
+2006-05-02 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-init.c, src/Makefile.am, configure.ac: The plugin directory
+ location is now provided by the autotools files instead of being
+ hardcoded in the Mission Control.
+
+ * mission-control.pc.in (pluginlibdir): We now provide the plugin
+ library location in the package configuration file for other
+ interested components (i.e. the filters)
+
+2006-04-28 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.[c|h], src/mcd-telepathy-handler.c: Main presence
+ is now updated when going autoaway thus fixing bug #23758.
+ Added just-in-time fetching of available presence states:
+ In case the presence interface doesn't exist yet when status
+ changes to connected but becomes available later, the presence
+ options are fetched when setting the account's presence. This fixes
+ the related race condition.
+
+2006-04-27 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control.[c|h]: Libmissioncontrol methods
+ will now check whether there are any enabled accounts before doing
+ anything that will invoke Mission Control. Initial experimental
+ code for the request cancellation support has been added, but it's
+ not yet tested.
+
+2006-04-25 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control.[c|h]
+ (mission_control_get_presence): We now check whether the Mission
+ Control is present on the D-BUS in order to avoid unnecessary
+ starting it up when we're offline and want to know our presence.
+
+ * src/mcd-dsm.c (mcd_shutdown_ind_cb): Mission Control will now
+ explicitly call close for all channels in order to fix the bug
+ #25155, in case there will be some connection manager that does
+ not do it while disconnecting a connection.
+
+2006-04-24 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-filtering.h: The channel type quark getter prototype
+ name mismatched the implementation. Fixed.
+
+ * src/mcd.h: Moved some definitions to mcd-filtering.h, because
+ plugins need access to the same D-BUS service.
+
+2006-04-23 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-dbus-services.c: Fixed a build breakage.
+
+2006-04-21 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-init.c (_mcd_inactivity_cb): Mission Control should now
+ no longer enter autoaway when there is an ongoing VOIP call.
+
+2006-04-21 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control.h, src/mcd.h,
+ src/mcd-dbus-services.c: Added MC_NO_ACCOUNTS_ERROR.
+ The error is sent in response to all the DBUS methods in case
+ there aren't any enabled accounts. MC also exits in that case.
+
+ * src/mcd-dbus-services.c: On channel requests in disconnected
+ state, presence setting is now read from GConf.
+
+ * src/mcd-init.c: Minor change on e_book_open() function call's
+ parameters to fix bug #26998.
+
+2006-04-20 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-filtering.c: Merged some upstream fixes from Andrei to
+ the VOIP mode handling.
+
+2006-04-19 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd.h: Added definitions for the MCE service calls.
+
+ * src/mcd-filtering.c (remove_channel_watch): When we have no
+ longer VOIP calls going, exit from VOIP mode to the normal mode by
+ sending a request to the MCE.
+ (add_channel_watch): When we have a VOIP call going, send a
+ request to the MCE to enter the VOIP mode.
+
+2006-04-12 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control.[c|h], src/mcd-object.c,
+ src/mcd-signals-marshal.list, src/mcd-filtering.c,
+ src/src/chan-handler.h, xml/mcd-dbus-services.xml,
+ libmissioncontrol/mission-control-signals-marshal.list: Provided
+ the requested further improvements in the libmissioncontrol error
+ reporting, so that individual clients get only error signals that
+ are relevant to them.
+
+ * src/mcd-filtering.[c|h]: The filtering API has been updated to
+ provide access to the RtcomAccount and RtcomProfile for the
+ current channel request. Also, the API now includes a helper for
+ getting the list of addresses for the participants of current
+ channel.
+
+2006-04-11 Naba Kumar <naba.kumar@nokia.com>
+
+ * configure.ac: Version number upgraded.
+
+ * xml/mcd-dbus-services.xml: The method definitions have been
+ changed to include the serial number of the operation. Error
+ signal has been added.
+
+ * debian/control (Depends): Added dependency for the galago-daemon
+ version that no longer appears to have issues when being started
+ by Mission Control.
+
+ * libmissioncontrol/mission-control.c: Support for receiving the
+ Error signal from the missioncontrol. Do not emit the signal based
+ on g_error anymore.
+
+ * src/mcd.h, libmissioncontrol/missioncontrol.h: The error domain
+ quark definition has been removed, as it's no longer used.
+
+ * src/mcd-init.c: The environmental variable check to determine
+ whether we should launch galago and friends has been disabled and
+ the startup is done by default.
+
+ * src/mcd-telepathy-handler.c: Use of some obsolete context
+ members has been removed, other cleanups.
+
+ * src/mcd-chan-handler.h (struct chan_handler_req_t): The channel
+ handler request structure has been cleaned of some now unnecessary
+ members. The channel type is now represented as a quark.
+
+ * src/mcd-filtering.[c|h]: The filtering context and the access
+ API for it had some cleanups. We also keep up a count of the
+ channel instances per channel type. Part of the fix for bug #25260
+ is also here.
+
+ * src/mcd-object.[c|h]: Support for the counting of channels per
+ channel type has been added. Some obsolete code has been
+ removed. We now emit error signal to provide applications calling
+ MCD through libmissioncontrol information about error situations
+ (bug #25260).
+
+ * src/mcd-dbus-services.c: We now emit error signal to provide
+ applications calling MCD through libmissioncontrol information
+ about error situations (bug #25260). Some obsolete code has been
+ eliminated.
+
+2006-04-09 Naba Kumar <naba.kumar@nokia.com>
+ * src/mcd-object.c, src/mcd-telepathy-handler.c: Rearranged
+ "destroy" signal disconnection and connection object unreferencing
+ so that MC behaves nicely when connecting accounts with invalid
+ passwords. Now MC also exits after last account disconnects. These
+ fix bug 25951.
+
+ * src/mcd-dbus-services.c: Reconnecting the accounts which were
+ lost due to a Connection Manager crash is now possible.
+
+ * src/mcd-object.c: Minor change to call tp_key_value_list_free
+ for freeing the keyval list
+
+2006-04-06 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control-signals-marshal.list: The
+ "error" signal signature has been added.
+
+ * src/mcd-dbus-services.c,
+ libmissioncontrol/missioncontrol.c,
+ libmissioncontrol/missioncontrol.h: Partial fix for the bug 25260;
+ instead of pringing warnings, MissionControl sets GError
+ approriately, so libmissioncontrol can emit error signals
+ instead. Libmissioncontrol will now also free the allocated
+ account names to avoid memory leaks (fixing bug 25272).
+
+ * src/mcd.h: Some definitions needed by bug 25260 work were added.
+
+2006-04-06 Naba Kumar <naba.kumar@nokia.com>
+ * src/mcd-init.c, src/mcd-object.[c|h]: Mission Control will now
+ listen for accidentally destroyed connections (for example when
+ a Connection Manager crashes).
+
+ * src/mcd-init.c, src/mcd-object.c, mcd-dbus-services.c: Fixed
+ emission of account-status-changed signal in case Connectivity
+ is lost during it's establishment.
+
+ * src/mcd-init.c, src/mcd-object.[c|h]: Added reading of
+ MC_RAISE_SERVICES environment variable to decide if external
+ daemons are started/stopped
+
+2006-04-05 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c (mcd_dispose, mcd_connect_all_accounts): The
+ shutdown/startup of Galago is currently disabled
+
+ * src/mcd-init.c: When Connectivity is lost, Mission Control will
+ wait for a moment and only then exit if Connectivity does not
+ return.
+
+ * src/mcd-filtering.[c|h]: Added getter for the self handle
+ property of the connection.
+
+2006-04-04 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-telepathy-handler.c: _mcd_free_presence_info was moved
+ into mcd-object.c and is now public.
+
+ * src/mcd-object.[c|h]: Mission Control will now start Galago when
+ accounts are connected and shut it when Mission Control exists.
+
+ * src/mcd-init.c (_mcd_read_account_settings): Minor memory leak
+ fixes
+
+2006-04-03 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.c: Minor changes to internal filter functionality
+ calls to be in sync with the naming conventions.
+
+ * src/mcd-filtering.[c|h]: Major updates to the context getters and
+ context structure.
+
+ * src/mcd-filtering-int.h: The filter processing internal function
+ definitions have been separated here.
+
+2006-03-30 Naba Kumar <naba.kumar@nokia.com>
+
+ * debian/control, debian/mission-control-dev.install
+ debian/changelog, debian/libmissioncontrol-dev.install
+ src/Makefile.am, configure.ac, mission-control.pc.in
+ Makefile.am: Split mission-control and filters and have
+ separate mission-control development package.
+
+ * filter-plugins/mcd-filter-common.h,
+ filter-plugins/mcd-text-filter-plugin.c,
+ filter-plugins/mcd-filter-plugins.h,
+ filter-plugins/mcd-filter-common.c,
+ filter-plugins/mcd-voip-filter-plugin.c: Moved the filters
+ to mission-control-filters/src in repository.
+
+ * filters-plugins/*: Removed dead directory.
+
+2006-03-30 Naba Kumar <naba.kumar@nokia.com>
+
+ * filter-plugins/Makefile.am (libmcd_text_filter_la_SOURCES)
+ (libmcd_voip_filter_la_SOURCES): While compiling plugins, also use
+ the new common plugin code file.
+
+ * filter-plugins/mcd-text-filter-plugin.[c|h]: As the plugins
+ shared most of their code, the overlapping part was moved into
+ separate source and header files. Minor error handling fixes also
+ included.
+
+2006-03-30 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-filtering.c: Naming of functions was unified a
+ bit. Error messages now include the function where things went
+ wrong. Memory allocation done with g_new0.
+
+2006-03-29 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-object.[c|h], src/mcd-telepathy-handler.c,
+ src/mcd-dbus-services.c, src/mcd-filtering.c,
+ src/mcd-chan-handler.h, filter-plugins/mcd-text-filter-plugin.c,
+ filter-plugins/mcd-voip-filter-plugin.c: The
+ (mission_control_request_channel_with_string_handle) now works
+ properly.
+
+2006-03-28 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/mission-control.[c|h]: API changes:
+ (mission_control_request_channel) no longer uses ChaVoAddress, but
+ takes the handle and handle type directly instead. Added
+ (mission_control_request_channel_with_string_handle) function as
+ requested.
+
+ * libmissioncontrol/chavo-utils.[c|h]: Chavo-utils have been made
+ obsolete and removed.
+
+ * src/mcd-main.c (main): While initializing the MC, use the new
+ getter function for the actual MC object.
+
+ * src/mcd-filtering.c: Changed the filtering implementation to
+ pluginize it. Added the support functions for the pluginized
+ filters (registration/unregistration, context manipulation etc).
+
+ * src/mcd-dbus-services.c (mcd_request_channel): Changed the
+ function API as requested to make the ChaVoAddress structure
+ unnecessary.
+ (mcd_request_channel_with_string_handle): Added initial version of
+ the channel request function variant that supports the handle as a
+ string.
+ (mcd_get_connection): Ensure that we do not attempt to access an
+ invalid TpConn object, which would cause a crash.
+
+ * src/mcd-telepathy-handler.c (_mcd_new_channel_handler): Collect
+ new channel requests with directionality info so that they can be
+ handled by the filter plugins.
+
+ * src/mcd-object.[c|h]: Clean the filter plugins and channel request
+ hash while disposing mission control. Mission Control has been
+ singletonized. Corresponding changes to the header.
+
+ * src/mcd-init.c: Load the filter plugins. Read only the enabled
+ accounts.
+
+ * filter-plugins/*, debian/mission-control.install, Makefile.am:
+ The filters have been separated to dynamically loadable libraries.
+
+2006-03-22 Naba Kumar <naba.kumar@nokia.com>
+
+ * libmissioncontrol/Makefile.am: Added util library to build
+ flags/libs.
+
+ * libmissioncontrol/chavo-utils.[c|h]: Removed the now obsolete
+ ChavoAccount definition, as well as its helper function.
+
+ * xml/mcd-dbus-services.xml: Updated RequestChannel method signature.
+
+ * src/mcd-dbus-services.c (mcd_request_channel): The channel type
+ is now a string, instead of an enum. Removed now unnecessary
+ mapping from an enum to a string.
+
+ * src/filter-type-voip.c (filter3_invoke_voipengine): Fixed a
+ couple of warnings by adding the missing casts.
+
+ * src/mcd-init.c (_mcd_read_account_settings): We progressed to
+ next item in a GList with g_slist_next. While it worked, it's not
+ really the right thing to do.
+
+ * libmissioncontrol/mission-control.[c|h]: Libmissioncontrol now
+ uses the string identifiers for the channels instead of the old
+ enum system. Libmissioncontrol now also uses RtcomAccounts instead
+ of the old ChavoAccount.
+
+ * configure.ac: Version number updated.
+
+2006-03-21 Naba Kumar <naba.kumar@nokia.com>
+
+ * configure.ac: Bumped up the version to 0.7. util library is no
+ longer a dependency (control file also updated
+ accordingly). util library version 0.0.3 or newer is required.
+
+ * src/mcd-init.c (_mcd_read_account_settings): Account settings
+ are now read with the util library instead of the deprecated
+ util library.
+
+2006-03-17 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-filtering.c (mcd_async_request_chan_callback): No longer
+ call the filter chain for outgoing requests (fixes bug #24105)
+
+2006-03-15 Naba Kumar <naba.kumar@nokia.com>
+
+ * configure.ac: Version number update.
+
+ * src/mcd-telepathy-handler.c (_mcd_free_presence_info): Presence
+ information memory handling fixes.
+
+ * src/mcd-object.[c|h] (_mcd_disconnect_account_from_hash): Emit the
+ AccountStatusChanged signal only if we're doing
+ auto-disconnect. PresenceUpdate signal handling/crash fix.
+
+ * src/filter-type-text.c: A missing licence header was added.
+
+ * src/mcd-init.c: Connectivity is now used only on
+ ARM. Connectivity handling fixes. When returning from autoaway,
+ preceding presence value is restored.Added listener for system
+ state events.
+
+ * src/mcd-filtering.c: A missing licence header was added. VOIP
+ filter support was added.
+
+ * src/Makefile.am (mission_control_SOURCES),
+ src/filter-type-voip.c: VOIP filter functions added to build.
+
+2006-03-08 Naba Kumar <naba.kumar@nokia.com>
+
+ * src/mcd-telepathy-handler.c (_mcd_status_changed_handler):
+ Support added for handling of pending channel requests.
+ * src/mcd-object.h: Added device state info structure needed for
+ the DSM filters.
+ * src/mcd-object.c, src/mcd-dbus-services: Support added for use
+ of Connectivity on ARM.
+ * src/mcd-init.c (mcd_init): Added setup for DSM event
+ monitoring. Also, support added for use of Connectivity on ARM.
+ * src/mcd-filtering.c: mcd_async_request_chan_callback moved here.
+ * src/Makefile.am (mission_control_SOURCES): mcd-dsm.c added to
+ build (Contains the callbacks for device state book-keeping).
+ * src/filter-type-text.c: Added filter functions for battery low,
+ display and keylock. Contacts plugin is again used.
+ * configure.ac: Version updated.
+
+
+2006-03-02 Naba Kumar <naba.kumar@nokia.com>
+
+ * configure.ac: Version updated to 0.2
+ * src/mission-control.[c|h]:
+ * src/mcd-object.[c|h]:
+ - Dispose handling problems should now be fixed.
+ * src/mcd-dbus-services.c: (_mcd_async_request_chan_callback) Some
+ missing error handling was added
+
+ * configure.ac:
+ * debian/control:
+ * src/mcd-object.[c|h]:
+ * src/mcd-filtering.[c|h]:
+ * src/mcd-init.c:
+ * src/filter-type-text.c
+ * src/mcd-telepathy-handler.c
+ - Added support for contact filtering, merged with other changes.
+
+ * src/mcd-dbus-services.c:
+ * src/mcd-object.[c|h]:
+ - AccountStatusChange signal support was completed and some
+ related presence handling bugs (at least #23194) fixed.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/INSTALL
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..3620667f
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = libmissioncontrol src xml doc server test
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libmissioncontrol.pc mission-control.pc
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/README
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 00000000..9e730364
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,134 @@
+AC_INIT(Makefile.am)
+AM_INIT_AUTOMAKE(mission-control, 4.17)
+AM_CONFIG_HEADER(config.h)
+
+AC_CANONICAL_HOST
+
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+AC_HEADER_STDC
+
+AM_CFLAGS="$CFLAGS -Wall -fno-strict-aliasing -ansi -DDMALLOC"
+
+AC_ARG_ENABLE(cast-checks, [ --disable-cast-checks compile with GLIB cast checks disabled],[cchecks=${enableval}],cchecks=yes)
+if test "x$cchecks" = "xno"; then
+ CFLAGS="$CFLAGS -DG_DISABLE_CAST_CHECKS"
+fi
+
+AC_ARG_ENABLE(asserts, [ --disable-asserts compile with GLIB assertions disabled],[asserts=${enableval}],asserts=yes)
+if test "x$asserts" = "xno"; then
+ CFLAGS="$CFLAGS -DG_DISABLE_ASSERTS"
+fi
+
+AC_ARG_ENABLE(checks, [ --disable-checks compile with GLIB checks disabled],[checks=${enableval}],checks=yes)
+if test "x$checks" = "xno"; then
+ CFLAGS="$CFLAGS -DG_DISABLE_CHECKS"
+fi
+
+AC_ARG_WITH(profiles_dir, AS_HELP_STRING([--with-profiles-dir=<path>],[Directory for storing profiles]))
+if test -z "$with_profiles_dir" ; then
+ PROFILES_DIR="/usr/share/mission-control/profiles"
+else
+ PROFILES_DIR=$with_profiles_dir
+fi
+AC_SUBST(PROFILES_DIR)
+AC_DEFINE_UNQUOTED(PROFILES_DIR,"$PROFILES_DIR", [Directory for storing profiles])
+
+
+AC_ARG_WITH(accounts_dir, AS_HELP_STRING([--with-accounts-dir=<path>],[Directory for storing accounts]))
+if test -z "$with_accounts_dir" ; then
+ ACCOUNTS_DIR="~/.mission-control/accounts"
+else
+ ACCOUNTS_DIR=$with_accounts_dir
+fi
+AC_SUBST(ACCOUNTS_DIR)
+AC_DEFINE_UNQUOTED(ACCOUNTS_DIR,"$ACCOUNTS_DIR", [Directory for storing accounts])
+
+
+AC_ARG_WITH(chandlers_dir, AS_HELP_STRING([--with-chandlers-dir=<path>],[Directory for channel handlers]))
+if test -z "$with_chandlers_dir" ; then
+ eval datadir_expanded="$datadir"
+ CHANDLERS_DIR="${datadir_expanded}/telepathy/managers"
+else
+ CHANDLERS_DIR=$with_chandlers_dir
+fi
+AC_SUBST(CHANDLERS_DIR)
+AC_DEFINE_UNQUOTED(CHANDLERS_DIR,"$CHANDLERS_DIR", [Directory for channel handlers])
+
+test_enabled="no"
+AC_MSG_CHECKING(whether to build tests)
+AC_ARG_ENABLE(tests,
+ [ --enable-tests build tests. default=no],
+ [
+ AC_MSG_RESULT(${enableval})
+ test_enabled="${enableval}"
+ ],
+ [
+ AC_MSG_RESULT(no)
+ test_enabled="no"
+ ]
+)
+AM_CONDITIONAL(HAVE_TESTS, [test x$test_enabled = xyes])
+
+server_enabled="yes"
+AC_MSG_CHECKING(whether to build the sample server)
+AC_ARG_ENABLE(server,
+ [ --enable-server build server. default=yes],
+ [
+ AC_MSG_RESULT(${enableval})
+ server_enabled="${enableval}"
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ server_enabled="yes"
+ ]
+)
+AM_CONDITIONAL(HAVE_SERVER, [test x$server_enabled = xyes])
+
+dnl ***************************************************************************
+dnl Check for marshal and enum generators
+dnl ***************************************************************************
+GLIB_GENMARSHAL="`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`"
+AC_SUBST(GLIB_GENMARSHAL)
+GLIB_MKENUMS="`$PKG_CONFIG --variable=glib_mkenums glib-2.0`"
+AC_SUBST(GLIB_MKENUMS)
+
+PKG_CHECK_MODULES(DBUS, [dbus-1 >= 0.51, dbus-glib-1 >= 0.51], have_dbus=yes, have_dbus=no)
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+
+PKG_CHECK_MODULES(TELEPATHY, libtelepathy >= 0.0.50)
+AC_SUBST(TELEPATHY_LIBS)
+AC_SUBST(TELEPATHY_CFLAGS)
+
+GCONF_REQUIRED_VERSION=2.0.0
+PKG_CHECK_MODULES(GCONF, gconf-2.0 >= $GCONF_REQUIRED_VERSION)
+AC_SUBST(GCONF_CFLAGS)
+AC_SUBST(GCONF_LIBS)
+
+PKG_CHECK_MODULES(GLIB, glib-2.0)
+AC_SUBST(GLIB_LIBS)
+AC_SUBST(GLIB_CFLAGS)
+
+GTK_DOC_CHECK([1.3])
+
+pluginlibdir=$libdir/mission-control
+AC_SUBST(pluginlibdir)
+
+AC_OUTPUT([
+Makefile \
+mission-control.pc \
+libmissioncontrol.pc \
+src/Makefile \
+xml/Makefile \
+doc/Makefile \
+test/Makefile \
+doc/reference/Makefile \
+libmissioncontrol/Makefile \
+server/Makefile \
+server/org.freedesktop.Telepathy.MissionControl.service
+])
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 00000000..dc5adb0f
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = reference
+
diff --git a/doc/mc-dbus-iface.html b/doc/mc-dbus-iface.html
new file mode 100644
index 00000000..45f84e6e
--- /dev/null
+++ b/doc/mc-dbus-iface.html
@@ -0,0 +1,296 @@
+<html>
+<head>
+<title>MissionControl</title>
+<style type="text/css">
+.interface:before {
+ content: "Interface ";
+}
+.interface {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding-left: 1em;
+ font-size: 1.6em;
+ background: #ccf;
+}
+.methods:before {
+ content: "Methods";
+ font-size: 1.5em;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding-left: 1em;
+ background: #ccf;
+ display: block;
+}
+.signals:before {
+ content: "Signals";
+ font-size: 1.5em;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding-left: 1em;
+ background: #ccf;
+ display: block;
+}
+.method H3, .signal H3 {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding-left: 1em;
+ font-size: 1.3em;
+ background: #ccf;
+}
+.parameters:before {
+ content: "Parameters:";
+ display: block;
+ padding-bottom: 0.5em;
+}
+.parameters, .return {
+ padding: 1em;
+}
+.return:before {
+ content: "Return value(s):";
+ display: block;
+ padding-bottom: 0.5em;
+}
+.enum {
+ display: block;
+ font-family: monospace;
+ padding-left: 1cm;
+}
+.enum P {
+ padding: 0;
+ margin: 0;
+ padding-left: 1em;
+ font-family: serif;
+}
+</style>
+</head>
+<body>
+<h1>Mission Control specifications</h1>
+<div class="interface">com.nokia.chavo.mission_control</div>
+<p>This is the DBus interface used by mission-control.
+
+<div class="methods">
+
+<div class="method">
+<h3>SetPresence ( i: presence, s: message ) -> None </h3>
+<p>Request a presence
+<div class="parameters">
+presence - any of the following values:
+<div class="enum">
+0 - MC_PRESENCE_UNSET<br>
+1 - MC_PRESENCE_OFFLINE<br>
+2 - MC_PRESENCE_AVAILABLE<br>
+3 - MC_PRESENCE_AWAY<br>
+4 - MC_PRESENCE_EXTENDED_AWAY<br>
+5 - MC_PRESENCE_HIDDEN<br>
+6 - MC_PRESENCE_DO_NOT_DISTURB<br>
+</div>
+message - NULL or a message string to specify along with the presence (typically with away presence).
+</div>
+</div>
+
+<div class="method">
+<h3>GetPresence ( ) -> i </h3>
+<p>Get the last requested presence.
+</div>
+
+<div class="method">
+<h3>GetPresenceActual ( ) -> i </h3>
+<p>Get the current presence (which could be different from the last requested presence).
+</div>
+
+<div class="method">
+<h3>RequestChannel ( s: account_name, s: type, u: handle, i: handle_type ) -> None </h3>
+<p>Request a channel for a given numeric handle.</p>
+<div class="parameters">
+account_name - the name of the account requesting the channel<br>
+type - a D-Bus interface name representing base channel type<br>
+handle - an integer handle representing a contact, room or list<br>
+handle_type - an integer representing the handle type<br>
+</div>
+</div>
+
+<div class="method">
+<h3>RequestChannelWithStringHandle ( s: account_name, s: type, s: handle, i: handle_type ) -> None </h3>
+<p>Request a channel for a given string handle.</p>
+<div class="parameters">
+account_name - the name of the account requesting the channel<br>
+type - a D-Bus interface name representing base channel type<br>
+handle - a string representing a contact, room or list<br>
+handle_type - an integer representing the handle type<br>
+</div>
+</div>
+
+<div class="method">
+<h3>CancelChannelRequest ( u: operation_id ) -> None </h3>
+<p>Cancel a channel request; if the channel has already been created, it will be destroyed.</p>
+<div class="parameters">
+operation_id - the unique id of the channel request operation. (<em>this is the <code>serial</code> parameter of the RequestChannelWithStringHandle call &mdash; specs are going to change soon, though</em>)<br>
+</div>
+</div>
+
+<div class="method">
+<h3>ConnectAllWithDefaultPresence ( ) -> None </h3>
+<p>Connect all accounts with the default online presence.
+</div>
+
+<div class="method">
+<h3>GetConnectionStatus ( s: account_name ) -> u </h3>
+<p>Get the connection status for the specified account.</p>
+<div class="parameters">
+account_name - the account to retrieve the status from<br>
+</div>
+<div class="return">
+A unsigned integer as defined in Telepathy:
+<div class="enum">
+0 - CONNECTION_STATUS_CONNECTED<br>
+1 - CONNECTION_STATUS_CONNECTING<br>
+2 - CONNECTION_STATUS_DISCONNECTED<br>
+</div>
+</div>
+</div>
+
+<div class="method">
+<h3>GetOnlineConnections ( ) -> as </h3>
+<p>Get the online connections.</p>
+<div class="return">
+An array of the names of the online accounts.
+</div>
+</div>
+
+<div class="method">
+<h3>GetConnection ( s: account_name ) -> s, o </h3>
+<p>Get the connection status for the specified account.</p>
+<div class="parameters">
+account_name - the account to retrieve the connection from<br>
+</div>
+<div class="return">
+s: the connection bus name<br>
+o: the connection object path
+</div>
+</div>
+
+<div class="method">
+<h3>GetAccountForConnection ( s: object_path ) -> s </h3>
+<p>Get the connection's account.</p>
+<div class="parameters">
+object_path - the connection's object path<br>
+</div>
+<div class="return">
+s: the account name<br>
+</div>
+</div>
+
+<div class="method">
+<h3>GetUsedChannelsCount ( s: type ) -> u </h3>
+<p>Get the number of channels of the specified type.</p>
+<div class="parameters">
+type - the channel type<br>
+</div>
+<div class="return">
+u: the number of existing channels of this type<br>
+</div>
+</div>
+
+</div>
+
+<div class="signals">
+
+<div class="signal">
+<h3>AccountStatusChanged ( u: status, u: presence, u: reason, s: account_id )</h3>
+<p>Emitted when the status of some account changes.
+<div class="parameters">
+status - the connection status of the account<br>
+presence - the presence status of the account</br>
+reason - the reason why the status change happened. Can be any of the following:
+<div class="enum">
+0 - TP_CONN_STATUS_REASON_NONE_SPECIFIED<br>
+1 - TP_CONN_STATUS_REASON_REQUESTED<br>
+2 - TP_CONN_STATUS_REASON_NETWORK_ERROR<br>
+3 - TP_CONN_STATUS_REASON_AUTHENTICATION_FAILED<br>
+4 - TP_CONN_STATUS_REASON_ENCRYPTION_ERROR<br>
+5 - TP_CONN_STATUS_REASON_NAME_IN_USE<br>
+6 - TP_CONN_STATUS_REASON_CERT_NOT_PROVIDED<br>
+7 - TP_CONN_STATUS_REASON_CERT_UNTRUSTED<br>
+8 - TP_CONN_STATUS_REASON_CERT_EXPIRED<br>
+9 - TP_CONN_STATUS_REASON_CERT_NOT_ACTIVATED<br>
+10 - TP_CONN_STATUS_REASON_CERT_HOSTNAME_MISMATCH<br>
+11 - TP_CONN_STATUS_REASON_CERT_FINGERPRINT_MISMATCH<br>
+12 - TP_CONN_STATUS_REASON_CERT_SELF_SIGNED<br>
+13 - TP_CONN_STATUS_REASON_CERT_OTHER_ERROR
+</div>
+account_id - the account whose status has changed
+</div>
+</div>
+
+<div class="signal">
+<h3>McdError ( u: serial, s: client_id, u: error_id )</h3>
+<p>Emitted on some error.
+<div class="parameters">
+serial - <em>operation ID, maybe it will get removed from the specs soon</em><br>
+client_id - the d-bus unique name of the client whose this error is meant to</br>
+error_id - the error code:
+<div class="enum">
+0 - MC_DISCONNECTED_ERROR<br>
+1 - MC_INVALID_HANDLE_ERROR<br>
+2 - MC_NO_MATCHING_CONNECTION_ERROR<br>
+3 - MC_INVALID_ACCOUNT_ERROR<br>
+4 - MC_PRESENCE_FAILURE_ERROR<br>
+5 - MC_NO_ACCOUNTS_ERROR<br>
+6 - MC_NETWORK_ERROR<br>
+7 - MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR<br>
+8 - MC_LOWMEM_ERROR<br>
+9 - MC_CHANNEL_REQUEST_GENERIC_ERROR<br>
+10 - MC_CHANNEL_BANNED_ERROR<br>
+11 - MC_CHANNEL_FULL_ERROR<br>
+12 - MC_CHANNEL_INVITE_ONLY_ERROR<br>
+13 - MC_LAST_ERROR
+</div>
+</div>
+</div>
+
+<div class="signal">
+<h3>PresenceStatusRequested ( u: presence )</h3>
+<p>Emitted when a presence has been requested.
+<div class="parameters">
+presence - the requested presence.
+</div>
+</div>
+
+<div class="signal">
+<h3>PresenceStatusActual ( u: presence )</h3>
+<p>Emitted when the actual presence changes.
+<div class="parameters">
+presence - the actual presence.
+</div>
+</div>
+
+<div class="signal">
+<h3>UsedChannelsCountChanged ( s: type, u: count )</h3>
+<p>Emitted when the actual presence changes.
+<div class="parameters">
+type - the type of the channels<br>
+count - the new number of the channels of this type
+</div>
+</div>
+
+<div class="signal">
+<h3>StatusActual ( u: status, u: presence )</h3>
+<p>Emitted when the accounts' status changes.
+<div class="parameters">
+status - Can be one of these values:<br>
+<div class="enum">
+0 - MC_STATUS_DISCONNECTED
+<p>When all accounts are disconnected.</p>
+1 - MC_STATUS_CONNECTING
+<p>When at least one account is connecting.</p>
+2 - MC_STATUS_CONNECTED
+<p>When at least one account is connected <em>and</em> none is connecting.</p>
+</div>
+presence - the last requested presence.
+</div>
+</div>
+
+</div>
+
+</body>
+</html>
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
new file mode 100644
index 00000000..43fa44b7
--- /dev/null
+++ b/doc/reference/Makefile.am
@@ -0,0 +1,74 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.6 at least.
+AUTOMAKE_OPTIONS = 1.6
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=mission-control
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting the functions and macros.
+# e.g. DOC_SOURCE_DIR=../../../gtk
+DOC_SOURCE_DIR=../../libmissioncontrol
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
+MKDB_OPTIONS=--sgml-mode --output-format=xml
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_srcdir)/libmissioncontrol/*.h
+CFILE_GLOB=$(top_srcdir)/libmissioncontrol/*.c
+
+# Header files to ignore when scanning.
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
+IGNORE_HFILES= mc-account-monitor-priv.h \
+ mc-account-priv.h \
+ mc-manager-priv.h \
+ mc-protocol-priv.h \
+ mc-client-lib-gen.h \
+ mission-control-signals-marshal.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+INCLUDES=-I../.. $(DBUS_CFLAGS) $(TELEPATHY_CFLAGS)
+GTKDOC_LIBS=$(top_builddir)/libmissioncontrol/libmissioncontrol.la $(GCONF_LIBS) $(GLIB_LIBS) $(DBUS_LIBS) $(TELEPATHY_LIBS)
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST +=
diff --git a/doc/reference/mission-control-docs.sgml b/doc/reference/mission-control-docs.sgml
new file mode 100644
index 00000000..12c153a8
--- /dev/null
+++ b/doc/reference/mission-control-docs.sgml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+ <bookinfo>
+ <title>Mission Control Reference Manual</title>
+ </bookinfo>
+
+ <chapter>
+ <title>Mission Control API reference</title>
+ <xi:include href="xml/mc-account.xml"/>
+ <xi:include href="xml/mc-profile.xml"/>
+ <xi:include href="xml/mc-manager.xml"/>
+ <xi:include href="xml/mc-protocol.xml"/>
+ <xi:include href="xml/mc-account-monitor.xml"/>
+ <xi:include href="xml/mc.xml"/>
+ <xi:include href="xml/mission-control.xml"/>
+ </chapter>
+</book>
diff --git a/doc/reference/mission-control-overrides.txt b/doc/reference/mission-control-overrides.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/doc/reference/mission-control-overrides.txt
diff --git a/doc/reference/mission-control-sections.txt b/doc/reference/mission-control-sections.txt
new file mode 100644
index 00000000..78ba1631
--- /dev/null
+++ b/doc/reference/mission-control-sections.txt
@@ -0,0 +1,182 @@
+<SECTION>
+<FILE>mc-account</FILE>
+<TITLE>McAccount</TITLE>
+McAccount
+mc_account_new
+McAccountSettingState
+mc_account_lookup
+mc_account_lookup_with_profile
+mc_account_lookup_with_vcard_field
+mc_account_free
+mc_account_clear_cache
+mc_account_create
+mc_account_delete
+mc_accounts_list
+mc_accounts_list_by_enabled
+mc_accounts_list_by_profile
+mc_accounts_list_by_vcard_field
+mc_accounts_list_free
+McAccountFilter
+mc_accounts_filter
+mc_account_get_unique_name
+mc_account_get_profile
+mc_account_get_display_name
+mc_account_set_display_name
+mc_account_get_normalized_name
+mc_account_set_normalized_name
+mc_account_is_enabled
+mc_account_set_enabled
+mc_account_get_param_boolean
+mc_account_get_param_int
+mc_account_get_param_string
+mc_account_get_params
+mc_account_set_param_boolean
+mc_account_set_param_int
+mc_account_set_param_string
+mc_account_unset_param
+mc_account_is_complete
+mc_account_exists_supporting_invisible
+mc_account_set_avatar
+mc_account_get_avatar
+<SUBSECTION Standard>
+MC_ACCOUNT
+MC_IS_ACCOUNT
+MC_TYPE_ACCOUNT
+mc_account_get_type
+MC_ACCOUNT_CLASS
+MC_IS_ACCOUNT_CLASS
+MC_ACCOUNT_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>mc-profile</FILE>
+McProfileCapabilityFlags
+<TITLE>McProfile</TITLE>
+McProfile
+mc_profile_new
+mc_profile_lookup
+mc_profile_lookup_default_for_vcard_field
+mc_profile_free
+mc_profile_clear_cache
+mc_profiles_list
+mc_profiles_list_by_vcard_field
+mc_profiles_free_list
+mc_profile_get_unique_name
+mc_profile_get_configuration_ui
+mc_profile_get_display_name
+mc_profile_get_icon_name
+mc_profile_get_branding_icon_name
+mc_profile_get_vcard_field
+mc_profile_get_default_account_domain
+mc_profile_get_supports_invisible
+mc_profile_get_protocol
+mc_profile_get_protocol_name
+mc_profile_is_default_for_vcard_field
+mc_profile_get_capabilities
+mc_profile_get_default_setting
+<SUBSECTION Standard>
+MC_PROFILE
+MC_IS_PROFILE
+MC_TYPE_PROFILE
+mc_profile_get_type
+MC_PROFILE_CLASS
+MC_IS_PROFILE_CLASS
+MC_PROFILE_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>mc-manager</FILE>
+<TITLE>McManager</TITLE>
+McManager
+mc_manager_lookup
+mc_manager_free
+mc_manager_clear_cache
+mc_managers_list
+mc_managers_free_list
+mc_manager_get_unique_name
+mc_manager_get_bus_name
+mc_manager_get_object_path
+<SUBSECTION Standard>
+MC_MANAGER
+MC_IS_MANAGER
+MC_TYPE_MANAGER
+mc_manager_get_type
+MC_MANAGER_CLASS
+MC_IS_MANAGER_CLASS
+MC_MANAGER_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>mc-protocol</FILE>
+<TITLE>McProtocol</TITLE>
+McProtocol
+mc_protocol_lookup
+mc_protocol_free
+mc_protocols_list
+mc_protocols_list_by_manager
+mc_protocols_free_list
+mc_protocol_get_manager
+mc_protocol_get_name
+mc_protocol_get_params
+mc_protocol_free_params_list
+mc_protocol_print
+<SUBSECTION Standard>
+MC_PROTOCOL
+MC_IS_PROTOCOL
+MC_TYPE_PROTOCOL
+mc_protocol_get_type
+MC_PROTOCOL_CLASS
+MC_IS_PROTOCOL_CLASS
+MC_PROTOCOL_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>mc-account-monitor</FILE>
+<TITLE>McAccountMonitor</TITLE>
+McAccountMonitor
+mc_account_monitor_new
+<SUBSECTION Standard>
+MC_ACCOUNT_MONITOR
+MC_IS_ACCOUNT_MONITOR
+MC_TYPE_ACCOUNT_MONITOR
+mc_account_monitor_get_type
+MC_ACCOUNT_MONITOR_CLASS
+MC_IS_ACCOUNT_MONITOR_CLASS
+MC_ACCOUNT_MONITOR_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>mc</FILE>
+mc_make_resident
+</SECTION>
+
+<SECTION>
+<FILE>mission-control</FILE>
+MissionControl
+MissionControlClass
+MCError
+McPresence
+McStatus
+McAccountStatus
+McCallback
+McGetCurrentStatusCallback
+missioncontrol
+missioncontrolclass
+mission_control_new
+mission_control_set_presence
+mission_control_get_presence
+mission_control_get_presence_actual
+mission_control_request_channel
+mission_control_request_channel_with_string_handle
+mission_control_cancel_channel_request
+mission_control_connect_all_with_default_presence
+mission_control_get_connection_status
+mission_control_get_online_connections
+mission_control_get_connection
+mission_control_get_account_for_connection
+mission_control_get_used_channels_count
+mission_control_get_current_status
+mission_control_free_account_statuses
+mission_control_remote_avatar_changed
+</SECTION>
+
diff --git a/doc/reference/mission-control.types b/doc/reference/mission-control.types
new file mode 100644
index 00000000..8f90607b
--- /dev/null
+++ b/doc/reference/mission-control.types
@@ -0,0 +1,9 @@
+#include <libmissioncontrol/mission-control.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+
+mission_control_get_type
+mc_account_monitor_get_type
+mc_account_get_type
+mc_profile_get_type
+mc_protocol_get_type
+mc_manager_get_type
diff --git a/doc/reference/tmpl/mc-account-monitor-priv.sgml b/doc/reference/tmpl/mc-account-monitor-priv.sgml
new file mode 100644
index 00000000..6ea0d92f
--- /dev/null
+++ b/doc/reference/tmpl/mc-account-monitor-priv.sgml
@@ -0,0 +1,16 @@
+<!-- ##### SECTION Title ##### -->
+mc-account-monitor-priv
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
diff --git a/doc/reference/tmpl/mc-account-monitor.sgml b/doc/reference/tmpl/mc-account-monitor.sgml
new file mode 100644
index 00000000..0edbed2d
--- /dev/null
+++ b/doc/reference/tmpl/mc-account-monitor.sgml
@@ -0,0 +1,70 @@
+<!-- ##### SECTION Title ##### -->
+McAccountMonitor
+
+<!-- ##### SECTION Short_Description ##### -->
+Monitor the accounts' status.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+The #McAccountMonitor is an object that raises signals when some changes have been made to one account. There are signals for account creation/deletion/change, and enabling/disabling.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### STRUCT McAccountMonitor ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL McAccountMonitor::account-changed ##### -->
+<para>
+
+</para>
+
+@mcaccountmonitor: the object which received the signal.
+@arg1:
+
+<!-- ##### SIGNAL McAccountMonitor::account-created ##### -->
+<para>
+
+</para>
+
+@mcaccountmonitor: the object which received the signal.
+@arg1:
+
+<!-- ##### SIGNAL McAccountMonitor::account-deleted ##### -->
+<para>
+
+</para>
+
+@mcaccountmonitor: the object which received the signal.
+@arg1:
+
+<!-- ##### SIGNAL McAccountMonitor::account-disabled ##### -->
+<para>
+
+</para>
+
+@mcaccountmonitor: the object which received the signal.
+@arg1:
+
+<!-- ##### SIGNAL McAccountMonitor::account-enabled ##### -->
+<para>
+
+</para>
+
+@mcaccountmonitor: the object which received the signal.
+@arg1:
+
+<!-- ##### FUNCTION mc_account_monitor_new ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
diff --git a/doc/reference/tmpl/mc-account-priv.sgml b/doc/reference/tmpl/mc-account-priv.sgml
new file mode 100644
index 00000000..bc135c67
--- /dev/null
+++ b/doc/reference/tmpl/mc-account-priv.sgml
@@ -0,0 +1,16 @@
+<!-- ##### SECTION Title ##### -->
+mc-account-priv
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
diff --git a/doc/reference/tmpl/mc-account.sgml b/doc/reference/tmpl/mc-account.sgml
new file mode 100644
index 00000000..c34ea61f
--- /dev/null
+++ b/doc/reference/tmpl/mc-account.sgml
@@ -0,0 +1,361 @@
+<!-- ##### SECTION Title ##### -->
+McAccount
+
+<!-- ##### SECTION Short_Description ##### -->
+MC's representation of an account.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A #McAccount stores all the informations required to use an account (login, password, #McProfile, etc.).
+</para>
+<para>
+The #McAccount API allows clients to manage accounts.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### STRUCT McAccount ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION mc_account_new ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
+<!-- ##### ENUM McAccountSettingState ##### -->
+<para>
+
+</para>
+
+@MC_ACCOUNT_SETTING_ABSENT:
+@MC_ACCOUNT_SETTING_FROM_ACCOUNT:
+@MC_ACCOUNT_SETTING_FROM_PROFILE:
+@MC_ACCOUNT_SETTING_FROM_PROXY:
+
+<!-- ##### FUNCTION mc_account_lookup ##### -->
+<para>
+
+</para>
+
+@unique_name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_lookup_with_profile ##### -->
+<para>
+
+</para>
+
+@profile:
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_lookup_with_vcard_field ##### -->
+<para>
+
+</para>
+
+@vcard_field:
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_free ##### -->
+<para>
+
+</para>
+
+@account:
+
+
+<!-- ##### FUNCTION mc_account_clear_cache ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION mc_account_create ##### -->
+<para>
+
+</para>
+
+@profile:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_delete ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_accounts_list ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
+<!-- ##### FUNCTION mc_accounts_list_by_enabled ##### -->
+<para>
+
+</para>
+
+@enabled:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_accounts_list_by_profile ##### -->
+<para>
+
+</para>
+
+@profile:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_accounts_list_by_vcard_field ##### -->
+<para>
+
+</para>
+
+@vcard_field:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_accounts_list_free ##### -->
+<para>
+
+</para>
+
+@list:
+
+
+<!-- ##### USER_FUNCTION McAccountFilter ##### -->
+<para>
+This function is called for every #McAccount in the list, and determines which elements have to be removed from the list.
+</para>
+
+@account: The #McAccount.
+@data: Pointer to user data.
+@Returns: %TRUE if the account must stay in the list, %FALSE if is must be removed.
+
+
+<!-- ##### FUNCTION mc_accounts_filter ##### -->
+<para>
+
+</para>
+
+@accounts:
+@filter:
+@data:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_unique_name ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_profile ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_display_name ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_display_name ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_normalized_name ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_normalized_name ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_is_enabled ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_enabled ##### -->
+<para>
+
+</para>
+
+@account:
+@enabled:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_param_boolean ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_param_int ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_param_string ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_params ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_param_boolean ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_param_int ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_param_string ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_unset_param ##### -->
+<para>
+
+</para>
+
+@account:
+@name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_is_complete ##### -->
+<para>
+
+</para>
+
+@account:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_set_avatar ##### -->
+<para>
+
+</para>
+
+@account:
+@filename:
+@mime_type:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_account_get_avatar ##### -->
+<para>
+
+</para>
+
+@account:
+@filename:
+@mime_type:
+@token:
+@Returns:
+
+
diff --git a/doc/reference/tmpl/mc-client-lib-gen.sgml b/doc/reference/tmpl/mc-client-lib-gen.sgml
new file mode 100644
index 00000000..7b87ad80
--- /dev/null
+++ b/doc/reference/tmpl/mc-client-lib-gen.sgml
@@ -0,0 +1,16 @@
+<!-- ##### SECTION Title ##### -->
+mc-client-lib-gen
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
diff --git a/doc/reference/tmpl/mc-manager-priv.sgml b/doc/reference/tmpl/mc-manager-priv.sgml
new file mode 100644
index 00000000..94387094
--- /dev/null
+++ b/doc/reference/tmpl/mc-manager-priv.sgml
@@ -0,0 +1,16 @@
+<!-- ##### SECTION Title ##### -->
+mc-manager-priv
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
diff --git a/doc/reference/tmpl/mc-manager.sgml b/doc/reference/tmpl/mc-manager.sgml
new file mode 100644
index 00000000..4b785ee4
--- /dev/null
+++ b/doc/reference/tmpl/mc-manager.sgml
@@ -0,0 +1,92 @@
+<!-- ##### SECTION Title ##### -->
+McManager
+
+<!-- ##### SECTION Short_Description ##### -->
+A representation of a connection manager.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A #McManager object represents a connection manager, that is the backend which can be used for handling one or more protocols.
+</para>
+<para>
+The #McManager API allows clients to query the available connection managers, and obtain their D-Bus coordinates.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### STRUCT McManager ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION mc_manager_lookup ##### -->
+<para>
+
+</para>
+
+@unique_name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_manager_free ##### -->
+<para>
+
+</para>
+
+@id:
+
+
+<!-- ##### FUNCTION mc_manager_clear_cache ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION mc_managers_list ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
+<!-- ##### FUNCTION mc_managers_free_list ##### -->
+<para>
+
+</para>
+
+@list:
+
+
+<!-- ##### FUNCTION mc_manager_get_unique_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_manager_get_bus_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_manager_get_object_path ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
diff --git a/doc/reference/tmpl/mc-profile.sgml b/doc/reference/tmpl/mc-profile.sgml
new file mode 100644
index 00000000..c06fb7fd
--- /dev/null
+++ b/doc/reference/tmpl/mc-profile.sgml
@@ -0,0 +1,219 @@
+<!-- ##### SECTION Title ##### -->
+McProfile
+
+<!-- ##### SECTION Short_Description ##### -->
+Account profiles.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A #McProfile represent a network service and stores some relevant about it,
+such as the underlying protocol, the supported channel types, the default
+server, etc. as well as some client-side information, such as the filename of
+the icon to be shown in association with it.
+</para>
+<para>
+The #McProfile API provides a way for managing profiles.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### ENUM McProfileCapabilityFlags ##### -->
+<para>
+
+</para>
+
+@MC_PROFILE_CAPABILITY_NONE:
+@MC_PROFILE_CAPABILITY_CHAT_P2P:
+@MC_PROFILE_CAPABILITY_CHAT_ROOM:
+@MC_PROFILE_CAPABILITY_CHAT_ROOM_LIST:
+@MC_PROFILE_CAPABILITY_VOICE_P2P:
+@MC_PROFILE_CAPABILITY_CONTACT_SEARCH:
+@MC_PROFILE_CAPABILITY_SPLIT_ACCOUNT:
+@MC_PROFILE_CAPABILITY_REGISTRATION_UI:
+@MC_PROFILE_CAPABILITY_SUPPORTS_AVATARS:
+
+<!-- ##### STRUCT McProfile ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION mc_profile_new ##### -->
+<para>
+
+</para>
+
+@unique_name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_lookup ##### -->
+<para>
+
+</para>
+
+@unique_name:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_lookup_default_for_vcard_field ##### -->
+<para>
+
+</para>
+
+@vcard_field:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_free ##### -->
+<para>
+
+</para>
+
+@id:
+
+
+<!-- ##### FUNCTION mc_profile_clear_cache ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION mc_profiles_list ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profiles_list_by_vcard_field ##### -->
+<para>
+
+</para>
+
+@vcard_field:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profiles_free_list ##### -->
+<para>
+
+</para>
+
+@list:
+
+
+<!-- ##### FUNCTION mc_profile_get_unique_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_configuration_ui ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_display_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_icon_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_branding_icon_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_vcard_field ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_default_account_domain ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_protocol ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_protocol_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_is_default_for_vcard_field ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_capabilities ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_profile_get_default_setting ##### -->
+<para>
+
+</para>
+
+@id:
+@setting:
+@Returns:
+
+
diff --git a/doc/reference/tmpl/mc-protocol-priv.sgml b/doc/reference/tmpl/mc-protocol-priv.sgml
new file mode 100644
index 00000000..0116a40a
--- /dev/null
+++ b/doc/reference/tmpl/mc-protocol-priv.sgml
@@ -0,0 +1,16 @@
+<!-- ##### SECTION Title ##### -->
+mc-protocol-priv
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
diff --git a/doc/reference/tmpl/mc-protocol.sgml b/doc/reference/tmpl/mc-protocol.sgml
new file mode 100644
index 00000000..4cf7d89c
--- /dev/null
+++ b/doc/reference/tmpl/mc-protocol.sgml
@@ -0,0 +1,112 @@
+<!-- ##### SECTION Title ##### -->
+McProtocol
+
+<!-- ##### SECTION Short_Description ##### -->
+representation of a communication protocol.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+An #McProtocol represents a protocol (such as Jabber, SIP, IRC...) and stores
+some parameters about it. It also specifies what is the backend (#McManager)
+which can handle this protocol.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### STRUCT McProtocol ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION mc_protocol_lookup ##### -->
+<para>
+
+</para>
+
+@id:
+@protocol:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_protocol_free ##### -->
+<para>
+
+</para>
+
+@id:
+
+
+<!-- ##### FUNCTION mc_protocols_list ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
+<!-- ##### FUNCTION mc_protocols_list_by_manager ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_protocols_free_list ##### -->
+<para>
+
+</para>
+
+@list:
+
+
+<!-- ##### FUNCTION mc_protocol_get_manager ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_protocol_get_name ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+
+<!-- ##### FUNCTION mc_protocol_get_params ##### -->
+<para>
+
+</para>
+
+@protocol:
+@Returns:
+<!-- # Unused Parameters # -->
+@param:
+
+
+<!-- ##### FUNCTION mc_protocol_free_params_list ##### -->
+<para>
+
+</para>
+
+@list:
+
+
+<!-- ##### FUNCTION mc_protocol_print ##### -->
+<para>
+
+</para>
+
+@protocol:
+
+
diff --git a/doc/reference/tmpl/mc.sgml b/doc/reference/tmpl/mc.sgml
new file mode 100644
index 00000000..67e067b0
--- /dev/null
+++ b/doc/reference/tmpl/mc.sgml
@@ -0,0 +1,23 @@
+<!-- ##### SECTION Title ##### -->
+mc
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION mc_make_resident ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/doc/reference/tmpl/mission-control-signals-marshal.sgml b/doc/reference/tmpl/mission-control-signals-marshal.sgml
new file mode 100644
index 00000000..844a6afa
--- /dev/null
+++ b/doc/reference/tmpl/mission-control-signals-marshal.sgml
@@ -0,0 +1,16 @@
+<!-- ##### SECTION Title ##### -->
+mission-control-signals-marshal
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
diff --git a/doc/reference/tmpl/mission-control-unused.sgml b/doc/reference/tmpl/mission-control-unused.sgml
new file mode 100644
index 00000000..e2354e9f
--- /dev/null
+++ b/doc/reference/tmpl/mission-control-unused.sgml
@@ -0,0 +1,256 @@
+<!-- ##### SECTION ./tmpl/mc-account-monitor-priv.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-account-monitor-priv.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-account-monitor-priv.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/mc-account-monitor-priv.sgml:Title ##### -->
+mc-account-monitor-priv
+
+
+<!-- ##### SECTION ./tmpl/mc-account-priv.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-account-priv.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-account-priv.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/mc-account-priv.sgml:Title ##### -->
+mc-account-priv
+
+
+<!-- ##### SECTION ./tmpl/mc-client-lib-gen.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-client-lib-gen.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-client-lib-gen.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/mc-client-lib-gen.sgml:Title ##### -->
+mc-client-lib-gen
+
+
+<!-- ##### SECTION ./tmpl/mc-manager-priv.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-manager-priv.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-manager-priv.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/mc-manager-priv.sgml:Title ##### -->
+mc-manager-priv
+
+
+<!-- ##### SECTION ./tmpl/mc-protocol-priv.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-protocol-priv.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mc-protocol-priv.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/mc-protocol-priv.sgml:Title ##### -->
+mc-protocol-priv
+
+
+<!-- ##### SECTION ./tmpl/mission-control-signals-marshal.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mission-control-signals-marshal.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/mission-control-signals-marshal.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/mission-control-signals-marshal.sgml:Title ##### -->
+mission-control-signals-marshal
+
+
+<!-- ##### MACRO DBUS_API_SUBJECT_TO_CHANGE ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO IS_MISSIONCONTROL ##### -->
+<para>
+
+</para>
+
+@obj:
+
+<!-- ##### MACRO IS_MISSIONCONTROL_CLASS ##### -->
+<para>
+
+</para>
+
+@klass:
+
+<!-- ##### MACRO MC_ERROR ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO MISSIONCONTROL ##### -->
+<para>
+
+</para>
+
+@obj:
+
+<!-- ##### MACRO MISSIONCONTROL_CLASS ##### -->
+<para>
+
+</para>
+
+@klass:
+
+<!-- ##### MACRO MISSIONCONTROL_GET_CLASS ##### -->
+<para>
+
+</para>
+
+@obj:
+
+<!-- ##### MACRO MISSIONCONTROL_TYPE ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO MISSION_CONTROL_IFACE ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO MISSION_CONTROL_PATH ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO MISSION_CONTROL_SERVICE ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### STRUCT McAccountMonitorClass ##### -->
+<para>
+
+</para>
+
+@parent_class:
+
+<!-- ##### ENUM OssoRtcomPresence ##### -->
+<para>
+
+</para>
+
+@OSSO_RTCOM_PRESENCE_UNSET:
+@OSSO_RTCOM_PRESENCE_OFFLINE:
+@OSSO_RTCOM_PRESENCE_AVAILABLE:
+@OSSO_RTCOM_PRESENCE_AWAY:
+@OSSO_RTCOM_PRESENCE_EXTENDED_AWAY:
+@OSSO_RTCOM_PRESENCE_HIDDEN:
+@OSSO_RTCOM_PRESENCE_DO_NOT_DISTURB:
+@LAST_OSSO_RTCOM_PRESENCE:
+@MC_PRESENCE_UNSET:
+@MC_PRESENCE_OFFLINE:
+@MC_PRESENCE_AVAILABLE:
+@MC_PRESENCE_AWAY:
+@MC_PRESENCE_EXTENDED_AWAY:
+@MC_PRESENCE_HIDDEN:
+@MC_PRESENCE_DO_NOT_DISTURB:
+@LAST_MC_PRESENCE:
+
+<!-- ##### FUNCTION mc_account_exists_supporting_invisible ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+<!-- ##### FUNCTION mc_profile_get_supports_invisible ##### -->
+<para>
+
+</para>
+
+@id:
+@Returns:
+
+<!-- ##### FUNCTION mission_control_cancel_last_request ##### -->
+<para>
+
+</para>
+
+@self:
+
+<!-- ##### FUNCTION mission_control_error_quark ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+<!-- ##### FUNCTION mission_control_get_type ##### -->
+<para>
+
+</para>
+
+@Returns:
+
diff --git a/doc/reference/tmpl/mission-control.sgml b/doc/reference/tmpl/mission-control.sgml
new file mode 100644
index 00000000..034ae433
--- /dev/null
+++ b/doc/reference/tmpl/mission-control.sgml
@@ -0,0 +1,316 @@
+<!-- ##### SECTION Title ##### -->
+mission-control
+
+<!-- ##### SECTION Short_Description ##### -->
+mission-control service API
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### TYPEDEF MissionControl ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL MissionControl::Error ##### -->
+<para>
+
+</para>
+
+@missioncontrol: the object which received the signal.
+@arg1:
+@arg2:
+
+<!-- ##### SIGNAL MissionControl::ServiceEnded ##### -->
+<para>
+
+</para>
+
+@missioncontrol: the object which received the signal.
+
+<!-- ##### TYPEDEF MissionControlClass ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ENUM MCError ##### -->
+<para>
+
+</para>
+
+@MC_DISCONNECTED_ERROR:
+@MC_INVALID_HANDLE_ERROR:
+@MC_NO_MATCHING_CONNECTION_ERROR:
+@MC_INVALID_ACCOUNT_ERROR:
+@MC_PRESENCE_FAILURE_ERROR:
+@MC_NO_ACCOUNTS_ERROR:
+@MC_NETWORK_ERROR:
+@MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR:
+@MC_LOWMEM_ERROR:
+@MC_CHANNEL_REQUEST_GENERIC_ERROR:
+@MC_CHANNEL_BANNED_ERROR:
+@MC_CHANNEL_FULL_ERROR:
+@MC_CHANNEL_INVITE_ONLY_ERROR:
+@MC_LAST_ERROR:
+
+<!-- ##### ENUM McPresence ##### -->
+<para>
+
+</para>
+
+@MC_PRESENCE_UNSET:
+@MC_PRESENCE_OFFLINE:
+@MC_PRESENCE_AVAILABLE:
+@MC_PRESENCE_AWAY:
+@MC_PRESENCE_EXTENDED_AWAY:
+@MC_PRESENCE_HIDDEN:
+@MC_PRESENCE_DO_NOT_DISTURB:
+@LAST_MC_PRESENCE:
+
+<!-- ##### ENUM McStatus ##### -->
+<para>
+
+</para>
+
+@MC_STATUS_DISCONNECTED:
+@MC_STATUS_CONNECTING:
+@MC_STATUS_CONNECTED:
+
+<!-- ##### STRUCT McAccountStatus ##### -->
+<para>
+
+</para>
+
+@unique_name:
+@status:
+@presence:
+@reason:
+
+<!-- ##### USER_FUNCTION McCallback ##### -->
+<para>
+Callback used for reporting errors from various #MissionControl calls.
+</para>
+
+@mc: the #MissionControl object.
+@error: if set, some error occurred. Must be freed.
+@user_data: user data specified when making the call request.
+
+
+<!-- ##### USER_FUNCTION McGetCurrentStatusCallback ##### -->
+<para>
+This callback is called in response to the #mission_control_get_current_status call, and carries in its parameters the information on #MissionControl status.
+</para>
+
+@mc: the #MissionControl object.
+@status: global connection status.
+@presence: global presence.
+@requested_presence: global requested presence.
+@accounts: array of #McAccountStatus structs which hold information about the status (connection and presence) of all enabled accounts. The callback is responsible to free this array by calling #mission_control_free_account_statuses.
+@n_accounts: number of accounts in the @accounts array.
+@error: if this is not %NULL, then some error occurred and all the status information is invalid. In that case, the callback has to free @error.
+@user_data: the user data specified when calling #mission_control_get_current_status.
+
+
+<!-- ##### STRUCT missioncontrol ##### -->
+<para>
+
+</para>
+
+@parent:
+@first_run:
+
+<!-- ##### STRUCT missioncontrolclass ##### -->
+<para>
+
+</para>
+
+@parent_class:
+
+<!-- ##### FUNCTION mission_control_new ##### -->
+<para>
+
+</para>
+
+@connection:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_set_presence ##### -->
+<para>
+
+</para>
+
+@self:
+@presence:
+@message:
+@callback:
+@user_data:
+
+
+<!-- ##### FUNCTION mission_control_get_presence ##### -->
+<para>
+
+</para>
+
+@self:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_get_presence_actual ##### -->
+<para>
+
+</para>
+
+@self:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_request_channel ##### -->
+<para>
+
+</para>
+
+@self:
+@account:
+@type:
+@handle:
+@handle_type:
+@callback:
+@user_data:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_request_channel_with_string_handle ##### -->
+<para>
+
+</para>
+
+@self:
+@account:
+@type:
+@handle:
+@handle_type:
+@callback:
+@user_data:
+@Returns:
+<!-- # Unused Parameters # -->
+@Handle_type:
+
+
+<!-- ##### FUNCTION mission_control_cancel_channel_request ##### -->
+<para>
+
+</para>
+
+@self:
+@operation_id:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_connect_all_with_default_presence ##### -->
+<para>
+
+</para>
+
+@self:
+@callback:
+@user_data:
+
+
+<!-- ##### FUNCTION mission_control_get_connection_status ##### -->
+<para>
+
+</para>
+
+@self:
+@account:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_get_online_connections ##### -->
+<para>
+
+</para>
+
+@self:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_get_connection ##### -->
+<para>
+
+</para>
+
+@self:
+@account:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_get_account_for_connection ##### -->
+<para>
+
+</para>
+
+@self:
+@connection:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_get_used_channels_count ##### -->
+<para>
+
+</para>
+
+@self:
+@type:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION mission_control_get_current_status ##### -->
+<para>
+
+</para>
+
+@self:
+@callback:
+@user_data:
+
+
+<!-- ##### FUNCTION mission_control_free_account_statuses ##### -->
+<para>
+
+</para>
+
+@accounts:
+
+
+<!-- ##### FUNCTION mission_control_remote_avatar_changed ##### -->
+<para>
+
+</para>
+
+@self:
+@connection:
+@contact_id:
+@token:
+@error:
+@Returns:
+
+
diff --git a/libmissioncontrol.pc.in b/libmissioncontrol.pc.in
new file mode 100644
index 00000000..a407f681
--- /dev/null
+++ b/libmissioncontrol.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+profiles_dir=@PROFILES_DIR@
+
+Name: libmissioncontrol
+Description: Mission Control Client Library
+Requires: dbus-1 >= 0.50, libtelepathy >= 0.0.1
+Version: @VERSION@
+Libs: -L${libdir} -lmissioncontrol -lmissioncontrol-config @DBUS_LIBS@
+Cflags: -I${includedir} @DBUS_CFLAGS@
diff --git a/libmissioncontrol/Makefile.am b/libmissioncontrol/Makefile.am
new file mode 100644
index 00000000..70d7c5d1
--- /dev/null
+++ b/libmissioncontrol/Makefile.am
@@ -0,0 +1,101 @@
+INCLUDES = $(DBUS_CFLAGS) $(TELEPATHY_CFLAGS) -I$(top_srcdir) \
+ -DMC_DISABLE_DEPRECATED \
+ -DLIBDIR="@libdir@" -DLIBVERSION="0"
+
+BUILT_SOURCES = \
+ mission-control-signals-marshal.c \
+ mission-control-signals-marshal.h \
+ mc-enum-types.c \
+ mc-enum-types.h \
+ mc-client-lib-gen.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+lib_LTLIBRARIES = libmissioncontrol-config.la libmissioncontrol.la
+
+libmissioncontrol_config_la_CFLAGS = $(GLIB_CFLAGS) $(GCONF_CFLAGS)
+libmissioncontrol_config_la_SOURCES = \
+ mc.c\
+ mc-manager.c \
+ mc-manager-priv.h \
+ mc-protocol.c \
+ mc-protocol-priv.h \
+ mc-profile.c \
+ mc-account.c \
+ mc-account-priv.h \
+ mc-account-monitor.c \
+ mc-account-monitor-priv.h \
+ mc-enum-types.c
+
+libmissioncontrol_config_includedir = $(includedir)/libmissioncontrol
+libmissioncontrol_config_include_DATA = \
+ mc.h \
+ mc-account.h \
+ mc-account-monitor.h \
+ mc-profile.h \
+ mc-protocol.h \
+ mc-manager.h
+
+libmissioncontrol_config_la_LIBADD = $(GCONF_LIBS) $(GLIB_LIBS) $(DBUS_LIBS)
+
+libmissioncontrol_config_la_LDFLAGS = $(common_ldflags) -export-symbols-regex "^mc_"
+
+libmissioncontrol_la_LIBADD = $(DBUS_LIBS) $(TELEPATHY_LIBS) \
+ libmissioncontrol-config.la
+
+libmissioncontrol_la_SOURCES = \
+ mission-control-signals-marshal.c \
+ mission-control.c
+
+mission_control_include = mission-control.h
+
+mc-client-lib-gen.h: ../xml/mcd-dbus-services.xml
+ dbus-binding-tool --prefix=mc-client-lib --mode=glib-client $< > $@
+
+%-marshal.h: %-marshal.list Makefile.am
+ glib-genmarshal --header --prefix=$(subst -,_,$*)_marshal $< > $*-marshal.h
+
+%-marshal.c: %-marshal.list Makefile.am
+ glib-genmarshal --body --prefix=$(subst -,_,$*)_marshal $< > $*-marshal.c
+
+mc-enum-types.h: stamp-mc-enum-types.h
+ @true
+stamp-mc-enum-types.h: Makefile $(mission_control_include) mc-enum-types.c
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#ifndef __MC_ENUM_TYPES_H__\n#define __MC_ENUM_TYPES_H__\n\n#include \"mission-control.h\"\n\nG_BEGIN_DECLS\n" \
+ --fprod "/* enumerations from \"@filename@\" */\n" \
+ --vhead "GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define MC_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
+ --ftail "G_END_DECLS\n\n#endif /* __MC_ENUM_TYPES_H__ */" \
+ $(mission_control_include) ) >> xgen-geth \
+ && (cmp -s xgen-geth mc-enum-types.h || cp xgen-geth mc-enum-types.h ) \
+ && rm -f xgen-geth \
+ && echo timestamp > $(@F)
+
+mc-enum-types.c: Makefile $(mission_control_include)
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#include \"mc-enum-types.h\"\n#define g_intern_static_string(s) (s)\n" \
+ --fprod "\n/* enumerations from \"@filename@\" */" \
+ --ftail "\n#define __MC_ENUM_TYPES_C__\n" \
+ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (g_intern_static_string (\"@EnumName@\"), values);\n }\n return etype;\n}\n" \
+ $(mission_control_include) ) > xgen-getc \
+ && cp xgen-getc mc-enum-types.c \
+ && rm -f xgen-getc
+
+bin_PROGRAMS = mc-account
+mc_account_SOURCES = mc-account-cli.c
+mc_account_LDADD = libmissioncontrol-config.la
+noinst_PROGRAMS = test
+test_SOURCES = test.c
+test_LDADD = libmissioncontrol-config.la
+
+missioncontrolincludeinstdir=$(includedir)/libmissioncontrol
+missioncontrolincludeinst_DATA = \
+ mission-control-signals-marshal.h \
+ mc-client-lib-gen.h \
+ mission-control.h
+
+EXTRA_DIST = \
+ $(missioncontrolincludeinst_DATA) \
+ $(libmissioncontrol_config_include_DATA)
diff --git a/libmissioncontrol/mc-account-cli.c b/libmissioncontrol/mc-account-cli.c
new file mode 100644
index 00000000..64df0ee0
--- /dev/null
+++ b/libmissioncontrol/mc-account-cli.c
@@ -0,0 +1,359 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include <glib-object.h>
+#include "mc-account.h"
+
+static gchar *app_name;
+
+static void
+show_help (gchar * err)
+{
+ if (err)
+ printf ("Error: %s\n", err);
+
+ printf ("Usage:\n"
+ " %1$s list\n"
+ " %1$s add <profile> <display name> string:account=<user_id> string:password=<password> [(int|bool|string):<key>=<value> ...]\n"
+ " %1$s set <account name> (int|bool|string):<key>=<value> [...]\n"
+ " %1$s display <account name> <display name>\n"
+ " %1$s show <account name>\n"
+ " %1$s enable <account name>\n"
+ " %1$s disable <account name>\n"
+ " %1$s delete <account name>\n",
+ app_name);
+
+ if (err)
+ exit (-1);
+ else
+ exit (0);
+}
+
+static void
+on_params_foreach (const gchar * key, const GValue * value)
+{
+ switch (G_VALUE_TYPE (value))
+ {
+ case G_TYPE_INT:
+ printf (" (int) %s = %d\n", key, g_value_get_int (value));
+ break;
+ case G_TYPE_UINT:
+ printf (" (int) %s = %d\n", key, g_value_get_uint (value));
+ break;
+ case G_TYPE_BOOLEAN:
+ printf (" (bool) %s = %s\n", key,
+ g_value_get_boolean (value) ? "true" : "false");
+ break;
+ case G_TYPE_STRING:
+ printf (" (string) %s = %s\n", key, g_value_get_string (value));
+ break;
+ default:
+ g_warning ("Unknown account setting type.");
+ }
+}
+
+static gboolean
+set_account_param (McAccount *account, gchar *param_value)
+{
+ gchar **strv_param_value = NULL;
+ gchar **strv_type_key = NULL;
+ const gchar *param, *type, *key, *value;
+ gboolean ret = FALSE;
+
+ if (!param_value)
+ return FALSE;
+
+ strv_param_value = g_strsplit (param_value, "=", -1);
+ if (strv_param_value[0] == NULL ||
+ strv_param_value[1] == NULL ||
+ strv_param_value[2] != NULL)
+ goto CLEANUP;
+ param = strv_param_value[0];
+ value = strv_param_value[1];
+
+ strv_type_key = g_strsplit (param, ":", -1);
+ if (strv_type_key[0] == NULL ||
+ strv_type_key[1] == NULL ||
+ strv_type_key[2] != NULL)
+ goto CLEANUP;
+ type = strv_type_key[0];
+ key = strv_type_key[1];
+
+ /* Set the key */
+ if (strcmp (type, "int") == 0)
+ {
+ mc_account_set_param_int (account, key, atoi (value));
+ ret = TRUE;
+ }
+ else if (strcmp (type, "bool") == 0)
+ {
+ mc_account_set_param_boolean (account, key, atoi (value));
+ ret = TRUE;
+ }
+ else if (strcmp (type, "string") == 0)
+ {
+ mc_account_set_param_string (account, key, value);
+ ret = TRUE;
+ }
+CLEANUP:
+ if (strv_param_value)
+ g_strfreev (strv_param_value);
+ if (strv_type_key)
+ g_strfreev (strv_type_key);
+ return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+ app_name = basename (argv[0]);
+
+ if (argc < 2)
+ show_help ("No command specified");
+
+ g_type_init ();
+ /* Command processing */
+
+ if (strcmp (argv[1], "add") == 0)
+ {
+ /* Add */
+ McProfile *profile;
+ McAccount *account;
+
+ if (argc < 6)
+ show_help ("Invalid add command.");
+
+ profile = mc_profile_lookup (argv[2]);
+ if (profile == NULL)
+ {
+ printf ("Error: No such profile: %s\n", argv[2]);
+ }
+ else
+ {
+ account = mc_account_create (profile);
+ if (account == NULL)
+ {
+ printf ("Error: Error creating account.\n");
+ }
+ else
+ {
+ const gchar *name;
+ gint i;
+ gboolean status = TRUE;
+
+ mc_account_set_display_name (account, argv[3]);
+ for (i = 4; i < argc; i++)
+ {
+ status = set_account_param (account, argv[i]);
+ if (!status)
+ break;
+ }
+ name = mc_account_get_unique_name (account);
+ if (!status)
+ {
+ mc_account_delete (account);
+ printf ("Account not added successfully: %s\n", name);
+ show_help ("Invalid account paramenters");
+ }
+ if (!mc_account_is_complete (account))
+ {
+ mc_account_delete (account);
+ printf ("Account not added successfully: %s\n", name);
+ show_help ("Given account paramenters does not define a complete account");
+ }
+ printf ("Account added successfully: %s\n", name);
+ g_object_unref (account);
+ }
+ g_object_unref (profile);
+ }
+ }
+ else if (strcmp (argv[1], "delete") == 0)
+ {
+ /* Delete account */
+ McAccount *account;
+
+ if (argc != 3)
+ show_help ("Invalid delete command.");
+
+ account = mc_account_lookup (argv[2]);
+ if (account == NULL)
+ {
+ printf ("Error: No such account: %s\n", argv[2]);
+ }
+ else
+ {
+ if (mc_account_delete (account))
+ {
+ printf ("Account %s deleted sucessfully.\n", argv[2]);
+ }
+ else
+ {
+ printf ("Error: Error deleting account: %s\n", argv[2]);
+ }
+ mc_account_free (account);
+ }
+ }
+ else if (strcmp (argv[1], "list") == 0)
+ {
+ /* List accounts */
+ GList *accounts, *tmp;
+
+ if (argc != 2)
+ show_help ("Invalid list command.");
+
+ accounts = mc_accounts_list ();
+ for (tmp = accounts; tmp != NULL; tmp = tmp->next)
+ {
+ McAccount *account;
+
+ account = (McAccount *) tmp->data;
+ printf ("%s (%s)\n",
+ mc_account_get_unique_name (account),
+ mc_account_get_display_name (account));
+
+ }
+ mc_accounts_list_free (accounts);
+ }
+ else if (strcmp (argv[1], "show") == 0)
+ {
+ /* Show account details */
+ McAccount *account;
+ GHashTable *params;
+
+ if (argc != 3)
+ show_help ("Invalid show command.");
+
+ account = mc_account_lookup (argv[2]);
+ if (account == NULL)
+ {
+ printf ("Error: No such account: %s\n", argv[2]);
+ exit (1);
+ }
+
+ params = mc_account_get_params (account);
+ if (params == NULL)
+ {
+ printf ("Error: Failed to retreive params: %s\n", argv[2]);
+ }
+ else
+ {
+ gboolean enabled;
+
+ enabled = mc_account_is_enabled (account);
+
+ printf (" Account: %s\n", argv[2]);
+ printf ("Display Name: %s\n", mc_account_get_display_name (account));
+ printf (" Enabled: %s\n\n", enabled ? "enabled" : "disabled");
+ g_hash_table_foreach (params, (GHFunc) on_params_foreach, NULL);
+
+ g_hash_table_destroy (params);
+ }
+ mc_account_free (account);
+ }
+ else if (strcmp (argv[1], "enable") == 0)
+ {
+ /* Enable account */
+ McAccount *account;
+
+ if (argc != 3)
+ show_help ("Invalid enable command.");
+
+ account = mc_account_lookup (argv[2]);
+ if (account == NULL)
+ {
+ printf ("Error: No such account: %s\n", argv[2]);
+ exit (-1);
+ }
+ mc_account_set_enabled (account, TRUE);
+ mc_account_free (account);
+ }
+ else if (strcmp (argv[1], "disable") == 0)
+ {
+ /* Disable account */
+ McAccount *account;
+
+ if (argc != 3)
+ show_help ("Invalid disable command.");
+
+ account = mc_account_lookup (argv[2]);
+ if (account == NULL)
+ {
+ printf ("Error: No such account: %s\n", argv[2]);
+ exit (-1);
+ }
+ mc_account_set_enabled (account, FALSE);
+ mc_account_free (account);
+ }
+ else if (strcmp (argv[1], "display") == 0)
+ {
+ /* Set display name */
+ McAccount *account;
+
+ if (argc != 4)
+ show_help ("Invalid display command.");
+
+ account = mc_account_lookup (argv[2]);
+ if (account == NULL)
+ {
+ printf ("Error: No such account: %s\n", argv[2]);
+ exit (-1);
+ }
+ mc_account_set_display_name (account, argv[3]);
+ mc_account_free (account);
+ }
+ else if (strcmp (argv[1], "set") == 0)
+ {
+ /* Set account parameter */
+ McAccount *account;
+
+ if (argc != 4)
+ show_help ("Invalid set command.");
+
+ account = mc_account_lookup (argv[2]);
+ if (!account)
+ {
+ printf ("Error: No such account: %s\n", argv[2]);
+ exit (-1);
+ }
+ if (!set_account_param (account, argv[3]))
+ {
+ show_help ("Invalid set command.");
+ }
+ g_object_unref (account);
+ }
+ else if (strcmp (argv[1], "help") == 0 ||
+ strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0)
+ {
+ show_help (NULL);
+ }
+ else
+ {
+ show_help ("Unknown command.");
+ }
+ return 0;
+}
diff --git a/libmissioncontrol/mc-account-monitor-priv.h b/libmissioncontrol/mc-account-monitor-priv.h
new file mode 100644
index 00000000..c55c2c3f
--- /dev/null
+++ b/libmissioncontrol/mc-account-monitor-priv.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_ACCOUNT_MONITOR_PRIV_H__
+#define __MC_ACCOUNT_MONITOR_PRIV_H__
+
+McAccount * _mc_account_monitor_lookup (McAccountMonitor *monitor, const gchar *unique_name);
+GList * _mc_account_monitor_list (McAccountMonitor *monitor);
+
+#endif /* __MC_ACCOUNT_MONITOR_PRIV_H__ */
+
diff --git a/libmissioncontrol/mc-account-monitor.c b/libmissioncontrol/mc-account-monitor.c
new file mode 100644
index 00000000..13ec2a8b
--- /dev/null
+++ b/libmissioncontrol/mc-account-monitor.c
@@ -0,0 +1,440 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <string.h>
+#include <strings.h>
+
+#include <gconf/gconf-client.h>
+
+#include "mc-account.h"
+#include "mc-account-priv.h"
+#include "mc-account-monitor.h"
+
+G_DEFINE_TYPE (McAccountMonitor, mc_account_monitor, G_TYPE_OBJECT);
+
+#define MC_ACCOUNT_MONITOR_PRIV(monitor) \
+ ((McAccountMonitorPrivate *)monitor->priv)
+
+enum
+{
+ SIGNAL_CREATED,
+ SIGNAL_DELETED,
+ SIGNAL_ENABLED,
+ SIGNAL_DISABLED,
+ SIGNAL_CHANGED,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS];
+
+typedef struct
+{
+ GConfClient *gconf_client;
+ guint gconf_connection;
+ GHashTable *accounts;
+ GHashTable *enabledness;
+} McAccountMonitorPrivate;
+
+static void
+mc_account_monitor_finalize (GObject *object)
+{
+ McAccountMonitor *self = MC_ACCOUNT_MONITOR (object);
+ McAccountMonitorPrivate *priv = MC_ACCOUNT_MONITOR_PRIV (self);
+
+ gconf_client_notify_remove (priv->gconf_client, priv->gconf_connection);
+ gconf_client_remove_dir (
+ priv->gconf_client, MC_ACCOUNTS_GCONF_BASE, NULL);
+
+ g_hash_table_destroy (priv->accounts);
+ g_hash_table_destroy (priv->enabledness);
+}
+
+static void
+mc_account_monitor_class_init (McAccountMonitorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McAccountMonitorPrivate));
+ object_class->finalize = mc_account_monitor_finalize;
+
+ /**
+ * McAccountMonitor::account-created:
+ * @self: The #McAccountMonitor.
+ * @name: The name of the account being created.
+ *
+ * Emitted when a new account is created.
+ */
+ signals[SIGNAL_CREATED] = g_signal_new (
+ "account-created",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+ /**
+ * McAccountMonitor::account-deleted:
+ * @self: The #McAccountMonitor.
+ * @name: The name of the account being deleted.
+ *
+ * Emitted when an account is deleted.
+ */
+ signals[SIGNAL_DELETED] = g_signal_new (
+ "account-deleted",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+ /**
+ * McAccountMonitor::account-enabled:
+ * @self: The #McAccountMonitor.
+ * @name: The name of the account being enabled.
+ *
+ * Emitted when an account is enabled.
+ */
+ signals[SIGNAL_ENABLED] = g_signal_new (
+ "account-enabled",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+ /**
+ * McAccountMonitor::account-disabled:
+ * @self: The #McAccountMonitor.
+ * @name: The name of the account being disabled.
+ *
+ * Emitted when an account is disabled.
+ */
+ signals[SIGNAL_DISABLED] = g_signal_new (
+ "account-disabled",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+ /**
+ * McAccountMonitor::account-changed:
+ * @self: The #McAccountMonitor.
+ * @name: The name of the account being changed.
+ *
+ * Emitted when an account is changed.
+ */
+ signals[SIGNAL_CHANGED] = g_signal_new (
+ "account-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static gchar *
+_account_name_from_key (const gchar *key)
+{
+ guint base_len = strlen (MC_ACCOUNTS_GCONF_BASE);
+ const gchar *base, *slash;
+
+ g_assert (key == strstr (key, MC_ACCOUNTS_GCONF_BASE));
+ g_assert (strlen (key) > base_len + 1);
+
+ base = key + base_len + 1;
+ slash = index (base, '/');
+
+ if (slash == NULL)
+ return g_strdup (base);
+ else
+ return g_strndup (base, slash - base);
+}
+
+static void
+_gconf_notify_cb (GConfClient *client, guint conn_id, GConfEntry *entry,
+ gpointer user_data)
+{
+ McAccountMonitor *monitor = MC_ACCOUNT_MONITOR (user_data);
+ McAccountMonitorPrivate *priv = MC_ACCOUNT_MONITOR_PRIV (monitor);
+ gchar *name = NULL;
+ McAccount *account;
+ gboolean key_is_enabledness;
+
+ key_is_enabledness = g_str_has_suffix (entry->key,
+ "/" MC_ACCOUNTS_GCONF_KEY_ENABLED);
+ name = _account_name_from_key (entry->key);
+ account = g_hash_table_lookup (priv->accounts, name);
+
+ /* Was account complete before? */
+ if (account == NULL)
+ {
+ account = _mc_account_new (name);
+
+ /* Account was not complete before and it just become complete */
+ if (mc_account_is_complete (account))
+ {
+ g_hash_table_insert (priv->accounts, g_strdup (name), account);
+ g_signal_emit (monitor, signals[SIGNAL_CREATED], 0, name);
+
+ /* check if the account is enabled and, in case, emit the respective
+ * signal */
+ if (mc_account_is_enabled (account))
+ {
+ g_hash_table_insert (priv->enabledness, g_strdup (name),
+ GINT_TO_POINTER (TRUE));
+ g_signal_emit (monitor, signals[SIGNAL_ENABLED], 0, name);
+ }
+ }
+ else
+ {
+ g_object_unref (account);
+ /* We don't do anything for incomplete accounts */
+ }
+ }
+ else if (g_str_has_suffix (entry->key, "/" MC_ACCOUNTS_GCONF_KEY_DELETED))
+ {
+ /* if account is deleted, remove it */
+ if (!mc_account_is_complete (account))
+ {
+ if (GPOINTER_TO_INT (g_hash_table_lookup (priv->enabledness, name)))
+ {
+ g_signal_emit (monitor, signals[SIGNAL_DISABLED], 0, name);
+ }
+ g_hash_table_remove (priv->accounts, name);
+ g_hash_table_remove (priv->enabledness, name);
+ g_signal_emit (monitor, signals[SIGNAL_DELETED], 0, name);
+ }
+ }
+ else if (g_str_has_suffix (entry->key, "/" MC_ACCOUNTS_GCONF_KEY_ENABLED))
+ {
+ if (entry->value != NULL && entry->value->type == GCONF_VALUE_BOOL)
+ {
+ if (gconf_value_get_bool (entry->value))
+ {
+ g_hash_table_insert (priv->enabledness, g_strdup (name),
+ GINT_TO_POINTER (TRUE));
+ g_signal_emit (monitor, signals[SIGNAL_ENABLED], 0, name);
+ }
+ else
+ {
+ g_hash_table_remove (priv->enabledness, name);
+ g_signal_emit (monitor, signals[SIGNAL_DISABLED], 0, name);
+ }
+ }
+ }
+ else if (!g_str_has_suffix (entry->key, "/" MC_ACCOUNTS_GCONF_KEY_AVATAR_TOKEN))
+ {
+ /* Emit the rest as value changed signal */
+ g_signal_emit (monitor, signals[SIGNAL_CHANGED], 0, name);
+ }
+
+ /* If we are enabling/disabling account */
+ g_free (name);
+}
+
+static void
+mc_account_monitor_init (McAccountMonitor *self)
+{
+ GError *error = NULL;
+ GConfClient *client = gconf_client_get_default ();
+ GSList *i, *dirs;
+ McAccountMonitorPrivate *priv;
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ MC_TYPE_ACCOUNT_MONITOR, McAccountMonitorPrivate);
+ priv = MC_ACCOUNT_MONITOR_PRIV (self);
+ priv->accounts = NULL;
+ priv->gconf_client = client;
+ dirs = gconf_client_all_dirs (client, MC_ACCOUNTS_GCONF_BASE, &error);
+
+ if (NULL != error)
+ {
+ g_print ("Error: %s\n", error->message);
+ g_assert_not_reached ();
+ }
+
+ priv->accounts = g_hash_table_new_full (
+ g_str_hash, g_str_equal, (GDestroyNotify) g_free, g_object_unref);
+ priv->enabledness = g_hash_table_new_full (
+ g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+
+ for (i = dirs; NULL != i; i = i->next)
+ {
+ gchar *name = _account_name_from_key (i->data);
+ McAccount *account = _mc_account_new (name);
+
+ /* Only pick up accounts which are not yet deleted. */
+ if (mc_account_is_complete (account))
+ {
+ g_hash_table_insert (priv->accounts, g_strdup (name), account);
+
+ if (mc_account_is_enabled (account))
+ g_hash_table_insert (priv->enabledness, g_strdup (name),
+ GINT_TO_POINTER (TRUE));
+ }
+ else
+ {
+ g_object_unref (account);
+ }
+ g_free (i->data);
+ g_free (name);
+ }
+
+ g_slist_free (dirs);
+
+ gconf_client_add_dir (
+ client, MC_ACCOUNTS_GCONF_BASE, GCONF_CLIENT_PRELOAD_NONE, &error);
+
+ if (NULL != error)
+ {
+ g_print ("Error: %s\n", error->message);
+ g_assert_not_reached ();
+ }
+
+ priv->gconf_connection = gconf_client_notify_add (
+ client, MC_ACCOUNTS_GCONF_BASE, _gconf_notify_cb, self, NULL, &error);
+
+ if (NULL != error)
+ {
+ g_print ("Error: %s\n", error->message);
+ g_assert_not_reached ();
+ }
+}
+
+McAccount *
+_mc_account_monitor_lookup (McAccountMonitor *monitor, const gchar *unique_name)
+{
+ McAccountMonitorPrivate *priv = MC_ACCOUNT_MONITOR_PRIV (monitor);
+ McAccount *ret;
+
+ g_return_val_if_fail (unique_name != NULL, NULL);
+ g_return_val_if_fail (*unique_name != '\0', NULL);
+
+ ret = g_hash_table_lookup (priv->accounts, unique_name);
+
+ if (NULL != ret)
+ g_object_ref (ret);
+
+ return ret;
+}
+
+/**
+ * mc_account_monitor_new:
+ *
+ * Get a #McAccountMonitor object. The object is a singleton: it is created
+ * only if another instance of itself is not alive, otherwise the same instance
+ * is returned.
+ *
+ * Returns: the #McAccountMonitor object.
+ */
+McAccountMonitor *
+mc_account_monitor_new (void)
+{
+ static McAccountMonitor *monitor = NULL;
+
+ if (NULL == monitor)
+ {
+ monitor = g_object_new (MC_TYPE_ACCOUNT_MONITOR, NULL);
+ g_object_add_weak_pointer (G_OBJECT (monitor), (gpointer) &monitor);
+ }
+
+ g_object_ref (monitor);
+ return monitor;
+}
+
+static void
+_list_append (gpointer key, gpointer value, gpointer user_data)
+{
+ GList **list = (GList **) user_data;
+
+ *list = g_list_prepend (*list, value);
+}
+
+GList *
+_mc_account_monitor_list (McAccountMonitor *monitor)
+{
+ McAccountMonitorPrivate *priv = MC_ACCOUNT_MONITOR_PRIV (monitor);
+ GList *accounts = NULL;
+
+ g_hash_table_foreach (priv->accounts, _list_append, &accounts);
+ return accounts;
+}
+
+static void
+merge_presences (gpointer key, McAccount *account, GArray *presences)
+{
+ const McPresence *account_presences;
+ gint i;
+
+ if (!mc_account_is_enabled (account))
+ return;
+
+ account_presences = mc_account_get_supported_presences (account);
+ if (account_presences)
+ {
+ while (*account_presences)
+ {
+ /* check if this presence is already in the array */
+ for (i = 0; i < presences->len; i++)
+ if (g_array_index (presences, McPresence, i) == *account_presences)
+ break;
+ if (i >= presences->len) /* no, it's not: let's add it */
+ g_array_append_vals (presences, account_presences, 1);
+ account_presences++;
+ }
+ }
+}
+
+/**
+ * mc_account_monitor_get_supported_presences:
+ * @monitor: The #McAccountMonitor.
+ *
+ * Get a list of all the presences supported in any account: a presence is
+ * considered as supported if there is at least one enabled account which
+ * supports it. Support fot the basic presences @MC_PRESENCE_AVAILABLE and
+ * @MC_PRESENCE_OFFLINE is taken for granted and therefore these presences are
+ * not returned.
+ *
+ * Returns: a NULL-terminated array of presences, which must be freed with
+ * g_free().
+ */
+McPresence *
+mc_account_monitor_get_supported_presences (McAccountMonitor *monitor)
+{
+ McAccountMonitorPrivate *priv = MC_ACCOUNT_MONITOR_PRIV (monitor);
+ GArray *presences;
+ McPresence *data;
+
+ presences = g_array_new (TRUE, FALSE, sizeof (McPresence));
+ g_hash_table_foreach (priv->accounts, (GHFunc)merge_presences, presences);
+ data = (McPresence *)presences->data;
+ g_array_free (presences, FALSE);
+ return data;
+}
+
diff --git a/libmissioncontrol/mc-account-monitor.h b/libmissioncontrol/mc-account-monitor.h
new file mode 100644
index 00000000..742117aa
--- /dev/null
+++ b/libmissioncontrol/mc-account-monitor.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_ACCOUNT_MONITOR_H__
+#define __MC_ACCOUNT_MONITOR_H__
+
+#include <glib-object.h>
+#include <libmissioncontrol/mission-control.h>
+
+G_BEGIN_DECLS
+
+#define MC_TYPE_ACCOUNT_MONITOR mc_account_monitor_get_type()
+
+#define MC_ACCOUNT_MONITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MC_TYPE_ACCOUNT_MONITOR, McAccountMonitor))
+
+#define MC_ACCOUNT_MONITOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MC_TYPE_ACCOUNT_MONITOR, McAccountMonitorClass))
+
+#define MC_IS_ACCOUNT_MONITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MC_TYPE_ACCOUNT_MONITOR))
+
+#define MC_IS_ACCOUNT_MONITOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MC_TYPE_ACCOUNT_MONITOR))
+
+#define MC_ACCOUNT_MONITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MC_TYPE_ACCOUNT_MONITOR, McAccountMonitorClass))
+
+typedef struct {
+ GObject parent;
+ gpointer priv;
+} McAccountMonitor;
+
+typedef struct {
+ GObjectClass parent_class;
+} McAccountMonitorClass;
+
+GType mc_account_monitor_get_type (void);
+
+McAccountMonitor* mc_account_monitor_new (void);
+
+McPresence * mc_account_monitor_get_supported_presences (McAccountMonitor *
+ monitor);
+
+G_END_DECLS
+
+#endif /* __MC_ACCOUNT_MONITOR_H__ */
diff --git a/libmissioncontrol/mc-account-priv.h b/libmissioncontrol/mc-account-priv.h
new file mode 100644
index 00000000..c287c153
--- /dev/null
+++ b/libmissioncontrol/mc-account-priv.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_ACCOUNT_PRIV_H__
+#define __MC_ACCOUNT_PRIV_H__
+
+#define MC_ACCOUNTS_GCONF_BASE "/apps/telepathy/mc/accounts"
+#define MC_ACCOUNTS_GCONF_KEY_DISPLAY_NAME "display_name"
+#define MC_ACCOUNTS_GCONF_KEY_NORMALIZED_NAME "normalized_name"
+#define MC_ACCOUNTS_GCONF_KEY_ENABLED "enabled"
+#define MC_ACCOUNTS_GCONF_KEY_DELETED "deleted"
+#define MC_ACCOUNTS_GCONF_KEY_PROFILE "profile"
+#define MC_ACCOUNTS_GCONF_KEY_PARAM_ACCOUNT "account"
+#define MC_ACCOUNTS_GCONF_KEY_AVATAR_TOKEN "avatar_token"
+#define MC_ACCOUNTS_GCONF_KEY_AVATAR_MIME "avatar_mime"
+#define MC_ACCOUNTS_GCONF_KEY_AVATAR_ID "avatar_id"
+#define MC_ACCOUNTS_GCONF_KEY_DATA_DIR "data_dir"
+
+McAccount * _mc_account_new (const gchar *unique_name);
+
+#endif /* __MC_ACCOUNT_PRIV_H__ */
+
diff --git a/libmissioncontrol/mc-account.c b/libmissioncontrol/mc-account.c
new file mode 100644
index 00000000..16212d75
--- /dev/null
+++ b/libmissioncontrol/mc-account.c
@@ -0,0 +1,2136 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+
+#include <dbus/dbus.h>
+#include <errno.h>
+#include <gconf/gconf-client.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib/gstdio.h>
+
+#include "mc-account.h"
+#include "mc-account-priv.h"
+#include "mc-account-monitor.h"
+#include "mc-account-monitor-priv.h"
+#include "mc-profile.h"
+#include <config.h>
+
+#define MC_ACCOUNTS_MAX 1024
+#define MC_AVATAR_FILENAME "avatar.bin"
+
+#define MC_ACCOUNT_PRIV(account) ((McAccountPrivate *)account->priv)
+
+G_DEFINE_TYPE (McAccount, mc_account, G_TYPE_OBJECT);
+
+typedef struct
+{
+ gchar *unique_name;
+ GSList *display_names;
+ GSList *normalized_names;
+} McAccountPrivate;
+
+static gboolean mc_account_set_deleted (McAccount *account, gboolean deleted);
+static gboolean mc_account_is_deleted (McAccount *account);
+
+static void
+mc_account_finalize (GObject *object)
+{
+ McAccount *self = MC_ACCOUNT(object);
+ McAccountPrivate *priv = MC_ACCOUNT_PRIV (self);
+
+ g_free (priv->unique_name);
+ g_slist_foreach (priv->display_names, (GFunc)g_free, NULL);
+ g_slist_free (priv->display_names);
+ g_slist_foreach (priv->normalized_names, (GFunc)g_free, NULL);
+ g_slist_free (priv->normalized_names);
+}
+
+static void
+mc_account_init (McAccount *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ MC_TYPE_ACCOUNT, McAccountPrivate);
+}
+
+void
+mc_account_clear_cache (void)
+{
+}
+
+McAccount *
+_mc_account_new (const gchar *unique_name)
+{
+ McAccount *new;
+ new = (McAccount *)g_object_new (MC_TYPE_ACCOUNT, NULL);
+ MC_ACCOUNT_PRIV (new)->unique_name = g_strdup (unique_name);
+
+ return new;
+}
+
+static void
+mc_account_class_init (McAccountClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McAccountPrivate));
+ object_class->finalize = mc_account_finalize;
+}
+
+/* Returns the data dir for the given account name.
+ * Returned string must be freed by caller. */
+static gchar *
+get_account_data_path (const gchar *unique_name)
+{
+ const gchar *base;
+
+ base = g_getenv ("MC_ACCOUNT_DIR");
+ if (!base)
+ base = ACCOUNTS_DIR;
+ if (!base)
+ return NULL;
+
+ if (base[0] == '~')
+ return g_build_filename (g_get_home_dir(), base + 1, unique_name, NULL);
+ else
+ return g_build_filename (base, unique_name, NULL);
+}
+
+/* if key is NULL, returns the gconf dir for the given account name,
+ * otherwise returns the full key. prepends key with param- if
+ * param is TRUE. returned string must be freed by caller. */
+static gchar *
+_mc_account_path (const gchar *unique_name,
+ const gchar *key,
+ gboolean param)
+{
+ if (key != NULL)
+ {
+ if (param)
+ {
+ return g_strconcat (MC_ACCOUNTS_GCONF_BASE, "/",
+ unique_name, "/param-",
+ key, NULL);
+ }
+ else
+ {
+ return g_strconcat (MC_ACCOUNTS_GCONF_BASE, "/",
+ unique_name, "/",
+ key, NULL);
+ }
+ }
+ else
+ {
+ return g_strconcat (MC_ACCOUNTS_GCONF_BASE, "/",
+ unique_name, NULL);
+ }
+}
+
+static GConfValue *
+_mc_account_gconf_get (McAccount *account,
+ const gchar *name,
+ gboolean param)
+{
+ GConfClient *client;
+ gchar *key;
+ GConfValue *value;
+
+ g_return_val_if_fail (account != NULL, NULL);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ name, param);
+ value = gconf_client_get (client, key, NULL);
+
+ g_object_unref (client);
+ g_free (key);
+
+ return value;
+}
+
+static gboolean
+_mc_account_gconf_get_boolean (McAccount *account,
+ const gchar *name,
+ gboolean param,
+ gboolean *value)
+{
+ GConfValue *val;
+
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ val = _mc_account_gconf_get (account, name, param);
+
+ if (val == NULL)
+ {
+ return FALSE;
+ }
+
+ if (val->type != GCONF_VALUE_BOOL)
+ {
+ gconf_value_free (val);
+ return FALSE;
+ }
+
+ *value = gconf_value_get_bool (val);
+ gconf_value_free (val);
+
+ return TRUE;
+}
+
+static gboolean
+_mc_account_gconf_get_int (McAccount *account,
+ const gchar *name,
+ gboolean param,
+ gint *value)
+{
+ GConfValue *val;
+
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ val = _mc_account_gconf_get (account, name, param);
+
+ if (val == NULL)
+ {
+ return FALSE;
+ }
+
+ if (val->type != GCONF_VALUE_INT)
+ {
+ gconf_value_free (val);
+ return FALSE;
+ }
+
+ *value = gconf_value_get_int (val);
+ gconf_value_free (val);
+
+ return TRUE;
+}
+
+static gboolean
+_mc_account_gconf_get_string (McAccount *account,
+ const gchar *name,
+ gboolean param,
+ gchar **value)
+{
+ GConfValue *val;
+
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ val = _mc_account_gconf_get (account, name, param);
+
+ if (val == NULL)
+ {
+ return FALSE;
+ }
+
+ if (val->type != GCONF_VALUE_STRING)
+ {
+ gconf_value_free (val);
+ return FALSE;
+ }
+
+ *value = g_strdup (gconf_value_get_string (val));
+ gconf_value_free (val);
+
+ return TRUE;
+}
+
+static gboolean
+_mc_account_gconf_set_string (McAccount *account, const gchar *name,
+ const gchar *value)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ name, FALSE);
+ ok = gconf_client_set_string (client, key, value, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+/**
+ * mc_account_lookup:
+ * @unique_name: The unique name of the account.
+ *
+ * Look-up an account from its unique name. The reference count of the returned
+ * account is not incremented.
+ *
+ * Return value: The requested #McAccount, or NULL if not found.
+ */
+McAccount *
+mc_account_lookup (const gchar *unique_name)
+{
+ McAccountMonitor *monitor = mc_account_monitor_new ();
+ McAccount *ret = _mc_account_monitor_lookup (monitor, unique_name);
+
+ g_object_unref (monitor);
+ return ret;
+}
+
+gboolean
+_filter_account (McAccount *acct, gpointer data)
+{
+ const gchar *compare_account;
+ gchar *gconf_account;
+ gboolean ret;
+
+ g_return_val_if_fail (acct != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (acct)->unique_name != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ compare_account = (const gchar *) data;
+
+ if (!_mc_account_gconf_get_string (acct,
+ MC_ACCOUNTS_GCONF_KEY_PARAM_ACCOUNT,
+ TRUE, &gconf_account))
+ return FALSE;
+
+ ret = (0 == strcmp(gconf_account, compare_account));
+
+ g_free (gconf_account);
+
+ return ret;
+}
+
+McAccount *
+_free_all_but_one (GList *list)
+{
+ McAccount *ret = NULL;
+
+ if (list != NULL)
+ {
+ GList *tmp;
+
+ tmp = g_list_remove_link (list, list);
+ mc_accounts_list_free (tmp);
+
+ ret = (McAccount *) list->data;
+ g_list_free (list);
+ }
+
+ return ret;
+}
+
+/**
+ * mc_account_lookup_with_profile:
+ * @profile: A #McProfile.
+ * @account: The name of the account.
+ *
+ * Look-up an account from its name in the given #McProfile. The reference
+ * count of the returned account is not incremented.
+ *
+ * Return value: The requested #McAccount, or NULL if not found.
+ */
+McAccount *
+mc_account_lookup_with_profile (McProfile *profile,
+ const gchar *account)
+{
+ GList *accounts;
+
+ g_return_val_if_fail (profile != NULL, NULL);
+ g_return_val_if_fail (account != NULL, NULL);
+
+ accounts = mc_accounts_list_by_profile (profile);
+ accounts = mc_accounts_filter (accounts, _filter_account, (gpointer) account);
+
+ return _free_all_but_one (accounts);
+}
+
+/**
+ * mc_account_lookup_with_vcard_field:
+ * @vcard_field: The VCard field.
+ * @account: The name of the account.
+ *
+ * Look-up an account from its name in the given VCard field. The reference
+ * count of the returned account is not incremented.
+ *
+ * Return value: The requested #McAccount, or NULL if not found.
+ */
+McAccount *
+mc_account_lookup_with_vcard_field (const gchar *vcard_field,
+ const gchar *account)
+{
+ GList *accounts;
+
+ g_return_val_if_fail (vcard_field != NULL, NULL);
+ g_return_val_if_fail (account != NULL, NULL);
+
+ accounts = mc_accounts_list_by_vcard_field (vcard_field);
+ accounts = mc_accounts_filter (accounts, _filter_account, (gpointer) account);
+
+ return _free_all_but_one (accounts);
+}
+
+/**
+ * mc_account_free:
+ * @account: The #McAccount.
+ *
+ * Free an account.
+ */
+void
+mc_account_free (McAccount* account)
+{
+ g_object_unref (account);
+}
+
+/**
+ * mc_account_create:
+ * @profile: A #McProfile.
+ *
+ * Create a new account of the given #McProfile.
+ *
+ * Return value: the newly created #McAccount.
+ */
+McAccount *
+mc_account_create (McProfile *profile)
+{
+ McAccount *ret = NULL;
+ GConfClient *client;
+ const gchar *profile_name;
+ gchar *unique_name, *key, *data_dir = NULL;
+ guint i = 0;
+ gboolean ok;
+
+ g_return_val_if_fail (profile != NULL, NULL);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ profile_name = mc_profile_get_unique_name (profile);
+
+ /* find the first free account with this profile */
+ unique_name = NULL;
+ while (unique_name == NULL && i < MC_ACCOUNTS_MAX)
+ {
+ gchar *path;
+
+ unique_name = g_strdup_printf ("%s%u", profile_name, i);
+
+ path = _mc_account_path (unique_name, NULL, FALSE);
+ if (gconf_client_dir_exists (client, path, NULL))
+ {
+ g_free (unique_name);
+ unique_name = NULL;
+ i++;
+ }
+ g_free (path);
+ }
+
+ if (unique_name == NULL)
+ goto OUT;
+
+ key = _mc_account_path (unique_name, MC_ACCOUNTS_GCONF_KEY_PROFILE, FALSE);
+ ok = gconf_client_set_string (client, key, profile_name, NULL);
+ g_free (key);
+
+ if (!ok)
+ goto OUT;
+
+ /* create the directory for storing the binary objects (i.e., avatar) */
+ data_dir = get_account_data_path (unique_name);
+ if (g_mkdir_with_parents (data_dir, 0777) != 0)
+ goto OUT;
+ /* and store it in GConf */
+ key = _mc_account_path (unique_name, MC_ACCOUNTS_GCONF_KEY_DATA_DIR, FALSE);
+ ok = gconf_client_set_string (client, key, data_dir, NULL);
+ g_free (key);
+
+ /* Account is disabled by default, because there is no guarantee
+ * the account is usable at this point. The one who created the
+ * account should enable it when its ready.
+ */
+ ret = _mc_account_new (unique_name);
+
+OUT:
+ g_free (data_dir);
+ g_free (unique_name);
+ g_object_unref (client);
+
+ return ret;
+}
+
+static gchar *
+_account_name_from_key (const gchar *key)
+{
+ guint base_len = strlen (MC_ACCOUNTS_GCONF_BASE);
+ const gchar *base, *slash;
+
+ g_assert (key == strstr (key, MC_ACCOUNTS_GCONF_BASE));
+ g_assert (strlen (key) > base_len + 1);
+
+ base = key + base_len + 1;
+ slash = strchr (base, '/');
+
+ if (slash == NULL)
+ return g_strdup (base);
+ else
+ return g_strndup (base, slash - base);
+}
+
+static gboolean
+mc_account_expunge_deleted (gpointer user_data)
+{
+ GConfClient *client;
+ gchar *key;
+ GSList *entries, *tmp;
+ gboolean ok = TRUE;
+ GError *error = NULL;
+ GSList *i, *dirs;
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ dirs = gconf_client_all_dirs (client, MC_ACCOUNTS_GCONF_BASE, &error);
+
+ if (NULL != error)
+ {
+ g_print ("Error: %s\n", error->message);
+ g_assert_not_reached ();
+ }
+ for (i = dirs; NULL != i; i = i->next)
+ {
+ gchar *unique_name = _account_name_from_key (i->data);
+ gchar *data_dir_str;
+ GDir *data_dir;
+
+ McAccount *account = _mc_account_new (unique_name);
+
+ if (!mc_account_is_deleted (account))
+ {
+ g_object_unref (account);
+ g_free (i->data);
+ g_free (unique_name);
+ continue;
+ }
+
+ key = _mc_account_path (unique_name, NULL, FALSE);
+ entries = gconf_client_all_entries (client, key, NULL);
+ g_free (key);
+
+ for (tmp = entries; tmp != NULL; tmp = tmp->next)
+ {
+ GConfEntry *entry;
+ entry = (GConfEntry*) tmp->data;
+
+ if (!gconf_client_unset (client, entry->key, NULL))
+ ok = FALSE;
+
+ gconf_entry_free (entry);
+ }
+
+ data_dir_str = get_account_data_path (unique_name);
+ data_dir = g_dir_open (data_dir_str, 0, NULL);
+ if (data_dir)
+ {
+ const gchar *filename;
+ while ((filename = g_dir_read_name (data_dir)) != NULL)
+ {
+ gchar *path;
+ path = g_build_filename (data_dir_str, filename, NULL);
+ g_remove (path);
+ g_free (path);
+ }
+ g_dir_close (data_dir);
+ g_rmdir (data_dir_str);
+ }
+ g_free (data_dir_str);
+
+ g_free (i->data);
+ g_free (unique_name);
+ g_slist_free (entries);
+ }
+ g_object_unref (client);
+ return FALSE;
+}
+
+/**
+ * mc_account_delete:
+ * @account: The #McAccount.
+ *
+ * Delete the given account from the accounts configuration. The object itself
+ * remains valid and must be free separately.
+ *
+ * Return value: %TRUE if the account was deleted, %FALSE otherwise.
+ */
+gboolean
+mc_account_delete (McAccount *account)
+{
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV(account)->unique_name != NULL,
+ FALSE);
+ mc_account_set_enabled (account, FALSE);
+
+ ok = mc_account_set_deleted (account, TRUE);
+
+ /* Expunge deleted accounts after 5 secs. We can't expunge the accounts
+ * immediately because there might be other people using the accounts
+ * and gconf signaling is really async.
+ */
+ g_timeout_add (2000, (GSourceFunc)mc_account_expunge_deleted, NULL);
+ return ok;
+}
+
+/**
+ * mc_accounts_list:
+ *
+ * Lists all configured accounts.
+ *
+ * Return value: a #GList of all accounts. Must be freed with
+ * #mc_accounts_list_free.
+ */
+GList *
+mc_accounts_list (void)
+{
+ McAccountMonitor *monitor = mc_account_monitor_new ();
+ GList *ret, *i;
+
+ ret = _mc_account_monitor_list (monitor);
+
+ for (i = ret; NULL != i; i = i->next)
+ g_object_ref (G_OBJECT (i->data));
+
+ g_object_unref (monitor);
+ return ret;
+}
+
+static gboolean
+_filter_enabled (McAccount *acct, gpointer data)
+{
+ gboolean enabled;
+
+ g_return_val_if_fail (acct != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (acct)->unique_name != NULL, FALSE);
+
+ enabled = GPOINTER_TO_INT (data);
+
+ return (mc_account_is_enabled (acct) == enabled);
+}
+
+/**
+ * mc_accounts_list_by_enabled:
+ * @enabled: a boolean to select if enabled accounts should be returned.
+ *
+ * Lists all enabled/disabled accounts.
+ *
+ * Return value: a #GList of all the enabled accounts. Must be freed with
+ * #mc_accounts_list_free.
+ */
+GList *
+mc_accounts_list_by_enabled (gboolean enabled)
+{
+ GList *ret;
+
+ ret = mc_accounts_list ();
+ ret = mc_accounts_filter (ret, _filter_enabled, GINT_TO_POINTER (enabled));
+
+ return ret;
+}
+
+static gboolean
+_filter_profile (McAccount *acct, gpointer data)
+{
+ McProfile *profile;
+ gchar *profile_name;
+ gboolean ret;
+
+ g_return_val_if_fail (acct != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (acct)->unique_name != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ profile = (McProfile *) data;
+
+ if (!_mc_account_gconf_get_string (acct, MC_ACCOUNTS_GCONF_KEY_PROFILE,
+ FALSE, &profile_name))
+ return FALSE;
+
+ ret = (0 == strcmp (profile_name, mc_profile_get_unique_name (profile)));
+ g_free (profile_name);
+
+ return ret;
+}
+
+/**
+ * mc_accounts_list_by_profile:
+ * @profile: a #McProfile.
+ *
+ * Lists all accounts of a #McProfile.
+ *
+ * Return value: a #GList of the accounts. Must be freed with
+ * #mc_accounts_list_free.
+ */
+GList *
+mc_accounts_list_by_profile (McProfile *profile)
+{
+ GList *ret;
+
+ g_return_val_if_fail (profile != NULL, NULL);
+
+ ret = mc_accounts_list ();
+ ret = mc_accounts_filter (ret, _filter_profile, profile);
+
+ return ret;
+}
+
+static gboolean
+_filter_vcard_field (McAccount *acct, gpointer data)
+{
+ McProfile *profile;
+ const gchar *vcard_field;
+ const gchar *profile_vcard_field;
+ gboolean ret;
+
+ g_return_val_if_fail (acct != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (acct)->unique_name != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ vcard_field = (const gchar *) data;
+ profile = mc_account_get_profile (acct);
+
+ if (profile == NULL)
+ return FALSE;
+
+ profile_vcard_field = mc_profile_get_vcard_field (profile);
+
+ if (profile_vcard_field == NULL)
+ ret = FALSE;
+ else
+ ret = (0 == strcmp (vcard_field, profile_vcard_field));
+
+ mc_profile_free (profile);
+ return ret;
+}
+
+/**
+ * mc_accounts_list_by_vcard_field:
+ * @vcard_field: the VCard field.
+ *
+ * Lists all accounts of a VCard field.
+ *
+ * Return value: a #GList of the accounts. Must be freed with
+ * #mc_accounts_list_free.
+ */
+GList *
+mc_accounts_list_by_vcard_field (const gchar *vcard_field)
+{
+ GList *ret;
+
+ ret = mc_accounts_list ();
+ ret = mc_accounts_filter (ret, _filter_vcard_field, (gpointer) vcard_field);
+
+ return ret;
+}
+
+/**
+ * mc_accounts_list_free:
+ * @list: A #GList of #McAccount.
+ *
+ * Frees the lists of accounts returned by the mc_accounts_list* family of
+ * functions.
+ */
+void
+mc_accounts_list_free (GList *list)
+{
+ GList *i;
+
+ for (i = list; NULL != i; i = i->next)
+ g_object_unref (G_OBJECT (i->data));
+
+ g_list_free (list);
+}
+
+/**
+ * mc_accounts_filter:
+ * @accounts: a #GList of #McAccount.
+ * @filter: a #McAccountFilter function.
+ * @data: user data to be passed to the filter function.
+ *
+ * Filter a list of accounts according to whether a function returns TRUE,
+ * freeing the list and any accounts which are filtered out.
+ *
+ * Return value: a #GList of the accounts. Must be freed with
+ * #mc_accounts_list_free.
+ */
+GList *
+mc_accounts_filter (GList *accounts,
+ McAccountFilter filter,
+ gpointer data)
+{
+ GList *tmp, *ret = NULL;
+
+ for (tmp = accounts; tmp != NULL; tmp = tmp->next)
+ {
+ McAccount *account = (McAccount *) tmp->data;
+
+ if (filter (account, data))
+ {
+ ret = g_list_prepend (ret, account);
+ }
+ else
+ {
+ mc_account_free (account);
+ }
+ }
+
+ g_list_free (accounts);
+
+ return ret;
+}
+
+/**
+ * mc_account_get_normalized_name:
+ * @account: The #McAccount.
+ *
+ * Gets the normalized name for the account.
+ *
+ * Return value: the normalized name (must free with #g_free), or NULL.
+ */
+const gchar *
+mc_account_get_normalized_name (McAccount *account)
+{
+ McAccountPrivate *priv;
+ GSList *list;
+ gchar *name;
+
+ g_return_val_if_fail (account != NULL, NULL);
+ priv = MC_ACCOUNT_PRIV (account);
+
+ if (!_mc_account_gconf_get_string (account,
+ MC_ACCOUNTS_GCONF_KEY_NORMALIZED_NAME,
+ FALSE, &name))
+ return NULL;
+
+ if ((list = g_slist_find_custom(priv->normalized_names, name,
+ (GCompareFunc)strcmp)) != NULL)
+ {
+ g_free (name);
+ name = list->data;
+ }
+ else
+ {
+ priv->normalized_names = g_slist_prepend (priv->normalized_names,
+ name);
+ }
+ return name;
+}
+
+/**
+ * mc_account_set_normalized_name:
+ * @account: The #McAccount.
+ * @name: The name to set.
+ *
+ * Sets the normalized name of the account.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurs.
+ */
+gboolean
+mc_account_set_normalized_name (McAccount *account, const gchar *name)
+{
+ return _mc_account_gconf_set_string (account,
+ MC_ACCOUNTS_GCONF_KEY_NORMALIZED_NAME,
+ name);
+}
+
+/**
+ * mc_account_get_unique_name:
+ * @account: The #McAccount.
+ *
+ * Gets the unique name for the account.
+ *
+ * Return value: the unique name, or NULL.
+ */
+const gchar *
+mc_account_get_unique_name (McAccount *account)
+{
+ g_return_val_if_fail (account != NULL, NULL);
+
+ return MC_ACCOUNT_PRIV (account)->unique_name;
+}
+
+/**
+ * mc_account_get_profile:
+ * @account: The #McAccount.
+ *
+ * Get the #McProfile this #McAccount belongs to.
+ *
+ * Return value: the #McProfile, or NULL.
+ */
+McProfile *
+mc_account_get_profile (McAccount *account)
+{
+ McProfile *ret;
+ gchar *profile_name;
+
+ g_return_val_if_fail (account != NULL, NULL);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ NULL);
+
+ if (!_mc_account_gconf_get_string (account, MC_ACCOUNTS_GCONF_KEY_PROFILE,
+ FALSE, &profile_name))
+ return NULL;
+
+ ret = mc_profile_lookup (profile_name);
+
+ g_free (profile_name);
+
+ return ret;
+}
+
+/**
+ * mc_account_get_display_name:
+ * @account: The #McAccount.
+ *
+ * Gets the display name for the account.
+ *
+ * Return value: the display name, or NULL.
+ */
+const gchar *
+mc_account_get_display_name (McAccount *account)
+{
+ McAccountPrivate *priv;
+ GSList *list;
+ gchar *name;
+
+ g_return_val_if_fail (account != NULL, NULL);
+ priv = MC_ACCOUNT_PRIV (account);
+
+ if (!_mc_account_gconf_get_string (account, MC_ACCOUNTS_GCONF_KEY_DISPLAY_NAME,
+ FALSE, &name))
+ return NULL;
+
+ if ((list = g_slist_find_custom(priv->display_names, name,
+ (GCompareFunc)strcmp)) != NULL)
+ {
+ g_free (name);
+ name = list->data;
+ }
+ else
+ {
+ priv->display_names = g_slist_prepend (priv->display_names, name);
+ }
+ return name;
+}
+
+/**
+ * mc_account_set_display_name:
+ * @account: The #McAccount.
+ * @name: The name to set.
+ *
+ * Sets the display name of the account.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurs.
+ */
+gboolean
+mc_account_set_display_name (McAccount *account, const gchar *name)
+{
+ return _mc_account_gconf_set_string (account,
+ MC_ACCOUNTS_GCONF_KEY_DISPLAY_NAME,
+ name);
+}
+
+/**
+ * mc_account_is_enabled:
+ * @account: The #McAccount.
+ *
+ * Checks if the account is enabled.
+ *
+ * Return value: %TRUE if enabled, %FALSE otherwise.
+ */
+gboolean
+mc_account_is_enabled (McAccount *account)
+{
+ gboolean enabled;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL, FALSE);
+
+ if (!_mc_account_gconf_get_boolean (account, MC_ACCOUNTS_GCONF_KEY_ENABLED,
+ FALSE, &enabled))
+ return FALSE;
+
+ return enabled;
+}
+
+static gboolean
+mc_account_is_deleted (McAccount *account)
+{
+ gboolean deleted;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL, FALSE);
+
+ if (!_mc_account_gconf_get_boolean (account, MC_ACCOUNTS_GCONF_KEY_DELETED,
+ FALSE, &deleted))
+ return FALSE;
+
+ return deleted;
+}
+
+static gboolean
+mc_account_set_deleted (McAccount *account, gboolean deleted)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL, FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_DELETED, FALSE);
+ ok = gconf_client_set_bool (client, key, deleted, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+/**
+ * mc_account_set_enabled:
+ * @account: The #McAccount.
+ * @enabled: whether the account must be enabled.
+ *
+ * Enables or disables an account.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_enabled (McAccount *account, const gboolean enabled)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL, FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ gconf_client_suggest_sync (client, NULL);
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_ENABLED, FALSE);
+ ok = gconf_client_set_bool (client, key, enabled, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+/**
+ * mc_account_get_param_boolean:
+ * @account: The #McAccount.
+ * @name: the parameter to retrieve.
+ * @value: a pointer to the boolean variable.
+ *
+ * Gets a boolean parameter from the account settings.
+ *
+ * Return value: a #McAccountSettingState.
+ */
+McAccountSettingState
+mc_account_get_param_boolean (McAccount *account,
+ const gchar *name,
+ gboolean *value)
+{
+ McAccountSettingState ret;
+
+ g_return_val_if_fail (account != NULL, MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (name != NULL, MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (value != NULL, MC_ACCOUNT_SETTING_ABSENT);
+
+ /* TODO: retreive type from protocol and check it matches */
+
+ ret = MC_ACCOUNT_SETTING_ABSENT;
+
+ if (_mc_account_gconf_get_boolean (account, name, TRUE, value))
+ {
+ ret = MC_ACCOUNT_SETTING_FROM_ACCOUNT;
+ }
+ else
+ {
+ McProfile *profile;
+ const gchar *def;
+
+ profile = mc_account_get_profile (account);
+ def = mc_profile_get_default_setting (profile, name);
+
+ if (def != NULL)
+ {
+ if (strcmp (def, "true") == 0 || strcmp (def, "1") == 0)
+ {
+ *value = TRUE;
+ ret = MC_ACCOUNT_SETTING_FROM_PROFILE;
+ }
+ else if (strcmp (def, "false") == 0 || strcmp (def, "0") == 0)
+ {
+ *value = FALSE;
+ ret = MC_ACCOUNT_SETTING_FROM_PROFILE;
+ }
+ else
+ {
+ g_warning ("%s: unable to parse boolean %s on account %s parameter %s",
+ G_STRFUNC, def, MC_ACCOUNT_PRIV (account)->unique_name,
+ name);
+ ret = MC_ACCOUNT_SETTING_ABSENT;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+_get_system_http_proxy (gboolean https, gchar **host, guint *port)
+{
+ gchar *ret_host;
+ guint ret_port;
+ GConfValue *value;
+ GConfClient *client = gconf_client_get_default ();
+
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ if (!https)
+ {
+ /* Plain HTTP. If use_http_proxy is not true, give up. */
+
+ value = gconf_client_get (
+ client, "/system/http_proxy/use_http_proxy", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_BOOL != value->type)
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ if (FALSE == gconf_value_get_bool (value))
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ gconf_value_free (value);
+
+ /* If we're supposed to authenticate, give up. */
+
+ value = gconf_client_get (
+ client, "/system/http_proxy/use_authentication", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_BOOL != value->type)
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ if (TRUE == gconf_value_get_bool (value))
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ gconf_value_free (value);
+ }
+
+ /* If the proxy mode is not manual (i.e. it's none or automatic), give up. */
+
+ value = gconf_client_get (client, "/system/proxy/mode", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_STRING != value->type)
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ if (0 != strcmp ("manual", gconf_value_get_string (value)))
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ gconf_value_free (value);
+
+ if (https)
+ {
+ value = gconf_client_get (client, "/system/proxy/secure_host", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_STRING != value->type)
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ ret_host = g_strdup (gconf_value_get_string (value));
+ gconf_value_free (value);
+ value = NULL;
+
+ value = gconf_client_get (client, "/system/proxy/secure_port", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_INT != value->type)
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ ret_port = gconf_value_get_int (value);
+ gconf_value_free (value);
+ }
+ else
+ {
+ value = gconf_client_get (client, "/system/http_proxy/host", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_STRING != value->type)
+ {
+ gconf_value_free (value);
+ goto NONE;
+ }
+
+ ret_host = g_strdup (gconf_value_get_string (value));
+ gconf_value_free (value);
+
+ value = gconf_client_get (client, "/system/http_proxy/port", NULL);
+
+ if (NULL == value)
+ goto NONE;
+
+ if (GCONF_VALUE_INT != value->type)
+ {
+ gconf_value_free (value);
+ g_free (ret_host);
+ goto NONE;
+ }
+
+ ret_port = gconf_value_get_int (value);
+ gconf_value_free (value);
+ }
+
+ if (0 == strcmp ("", ret_host) || ret_port <= 0)
+ {
+ g_free (ret_host);
+ goto NONE;
+ }
+
+ g_object_unref (client);
+ *host = ret_host;
+ *port = ret_port;
+ return TRUE;
+
+NONE:
+ g_object_unref (client);
+ return FALSE;
+}
+
+/**
+ * mc_account_get_param_int:
+ * @account: The #McAccount.
+ * @name: the parameter to retrieve.
+ * @value: a pointer to the integer variable.
+ *
+ * Gets a integer parameter from the account settings.
+ *
+ * Return value: a #McAccountSettingState.
+ */
+McAccountSettingState
+mc_account_get_param_int (McAccount *account,
+ const gchar *name,
+ gint *value)
+{
+ gchar *end;
+ glong long_val;
+ gint int_val;
+ McProfile *profile;
+ const gchar *def;
+
+ g_return_val_if_fail (account != NULL, MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (name != NULL, MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (value != NULL, MC_ACCOUNT_SETTING_ABSENT);
+
+ /* TODO: retreive type from protocol and check it matches */
+
+ if (_mc_account_gconf_get_int (account, name, TRUE, value))
+ return MC_ACCOUNT_SETTING_FROM_ACCOUNT;
+
+ profile = mc_account_get_profile (account);
+ def = mc_profile_get_default_setting (profile, name);
+
+ if (def != NULL)
+ {
+ errno = 0;
+ long_val = strtol (def, &end, 10);
+
+ if (*def == '\0' || *end != '\0')
+ {
+ g_warning ("%s: unable to parse integer %s on account %s parameter %s",
+ G_STRFUNC, def, MC_ACCOUNT_PRIV (account)->unique_name,
+ name);
+ return MC_ACCOUNT_SETTING_ABSENT;
+ }
+
+ int_val = long_val;
+
+ if (int_val != long_val || errno == ERANGE)
+ {
+ g_warning ("%s: integer %s out of range on account %s parameter %s",
+ G_STRFUNC, def, MC_ACCOUNT_PRIV (account)->unique_name,
+ name);
+ return MC_ACCOUNT_SETTING_ABSENT;
+ }
+
+ *value = int_val;
+ return MC_ACCOUNT_SETTING_FROM_PROFILE;
+ }
+
+ if (0 == strcmp(name, "http-proxy-port") ||
+ 0 == strcmp(name, "https-proxy-port"))
+ {
+ gchar *host;
+ guint port;
+ gboolean https;
+
+ if (0 == strcmp (name, "https-proxy-port"))
+ https = TRUE;
+ else
+ https = FALSE;
+
+ if (_get_system_http_proxy (https, &host, &port))
+ {
+ *value = port;
+ return MC_ACCOUNT_SETTING_FROM_PROXY;
+ }
+ }
+
+ return MC_ACCOUNT_SETTING_ABSENT;
+}
+
+/**
+ * mc_account_get_param_string:
+ * @account: The #McAccount.
+ * @name: the parameter to retrieve.
+ * @value: a pointer to the string variable which will receive the setting.
+ *
+ * Gets a string parameter from the account settings. The string will have to
+ * be freed with #g_free.
+ *
+ * Return value: a #McAccountSettingState.
+ */
+McAccountSettingState
+mc_account_get_param_string (McAccount *account,
+ const gchar *name,
+ gchar **value)
+{
+ McProfile *profile;
+ const gchar *def;
+
+ g_return_val_if_fail (account != NULL, MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (name != NULL, MC_ACCOUNT_SETTING_ABSENT);
+ g_return_val_if_fail (value != NULL, MC_ACCOUNT_SETTING_ABSENT);
+
+ /* TODO: retreive type from protocol and check it matches */
+
+ if (_mc_account_gconf_get_string (account, name, TRUE, value))
+ return MC_ACCOUNT_SETTING_FROM_ACCOUNT;
+
+ profile = mc_account_get_profile (account);
+ def = mc_profile_get_default_setting (profile, name);
+
+ if (def != NULL)
+ {
+ *value = g_strdup (def);
+ return MC_ACCOUNT_SETTING_FROM_PROFILE;
+ }
+
+ if (0 == strcmp(name, "http-proxy-server") ||
+ 0 == strcmp(name, "https-proxy-server"))
+ {
+ gchar *host;
+ guint port;
+ gboolean https;
+
+ if (0 == strcmp (name, "https-proxy-server"))
+ https = TRUE;
+ else
+ https = FALSE;
+
+ if (_get_system_http_proxy (https, &host, &port))
+ {
+ *value = host;
+ return MC_ACCOUNT_SETTING_FROM_PROXY;
+ }
+ }
+
+ return MC_ACCOUNT_SETTING_ABSENT;
+}
+
+/**
+ * mc_account_set_param_boolean:
+ * @account: The #McAccount.
+ * @name: the parameter to set.
+ * @value: a boolean value.
+ *
+ * Sets a boolean parameter in the account settings.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_param_boolean (McAccount *account,
+ const gchar *name,
+ gboolean value)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name, name,
+ TRUE);
+ ok = gconf_client_set_bool (client, key, value, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+/**
+ * mc_account_set_param_int:
+ * @account: The #McAccount.
+ * @name: the parameter to set.
+ * @value: a integer value.
+ *
+ * Sets a integer parameter in the account settings.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_param_int (McAccount *account,
+ const gchar *name,
+ gint value)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name, name,
+ TRUE);
+ ok = gconf_client_set_int (client, key, value, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+/**
+ * mc_account_set_param_string:
+ * @account: The #McAccount.
+ * @name: the parameter to set.
+ * @value: a string value.
+ *
+ * Sets a string parameter in the account settings.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_param_string (McAccount *account,
+ const gchar *name,
+ const gchar *value)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name, name,
+ TRUE);
+ ok = gconf_client_set_string (client, key, value, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+/**
+ * mc_account_unset_param:
+ * @account: The #McAccount.
+ * @name: the parameter to unset.
+ *
+ * Unsets (removes) a parameter from the account settings.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_unset_param (McAccount *account, const gchar *name)
+{
+ McAccountPrivate *priv = MC_ACCOUNT_PRIV (account);
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (priv->unique_name, name, TRUE);
+ ok = gconf_client_unset (client, key, NULL);
+
+ g_free (key);
+ g_object_unref (client);
+
+ return ok;
+}
+
+static void
+_g_value_free (gpointer data)
+{
+ GValue *value = (GValue *) data;
+ g_value_unset (value);
+ g_free (value);
+}
+
+static void
+_add_one_setting (McAccount *account,
+ McProtocolParam *param,
+ GHashTable *hash)
+{
+ GValue *value = NULL;
+ McAccountSettingState ret = MC_ACCOUNT_SETTING_ABSENT;
+
+ g_return_if_fail (account != NULL);
+ g_return_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL);
+ g_return_if_fail (param != NULL);
+ g_return_if_fail (param->name != NULL);
+ g_return_if_fail (param->signature != NULL);
+
+ switch (param->signature[0])
+ {
+ case DBUS_TYPE_STRING:
+ {
+ char *tmp;
+ ret = mc_account_get_param_string (account, param->name, &tmp);
+ if (ret != MC_ACCOUNT_SETTING_ABSENT)
+ {
+ value = g_new0(GValue, 1);
+ g_value_init (value, G_TYPE_STRING);
+ g_value_take_string (value, tmp);
+ }
+ break;
+ }
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_INT32:
+ {
+ gint tmp;
+ ret = mc_account_get_param_int (account, param->name, &tmp);
+ if (ret != MC_ACCOUNT_SETTING_ABSENT)
+ {
+ value = g_new0(GValue, 1);
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, tmp);
+ }
+ break;
+ }
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_UINT32:
+ {
+ gint tmp;
+ ret = mc_account_get_param_int (account, param->name, &tmp);
+ if (ret != MC_ACCOUNT_SETTING_ABSENT)
+ {
+ value = g_new0(GValue, 1);
+ g_value_init (value, G_TYPE_UINT);
+ g_value_set_uint (value, tmp);
+ }
+ break;
+ }
+ case DBUS_TYPE_BOOLEAN:
+ {
+ gboolean tmp;
+ ret = mc_account_get_param_boolean (account, param->name, &tmp);
+ if (ret != MC_ACCOUNT_SETTING_ABSENT)
+ {
+ value = g_new0(GValue, 1);
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, tmp);
+ }
+ break;
+ }
+ default:
+ g_warning ("%s: skipping parameter %s, unknown type %s", G_STRFUNC, param->name, param->signature);
+ }
+
+ if (ret != MC_ACCOUNT_SETTING_ABSENT && hash != NULL)
+ {
+ g_return_if_fail (value != NULL);
+ g_hash_table_insert (hash, g_strdup (param->name), value);
+ }
+}
+
+static gboolean
+copy_file (const gchar *filename_in, const gchar *filename_out)
+{
+ FILE *f_in, *f_out;
+ char buffer[2048];
+ size_t read, written;
+ gboolean ret = TRUE;
+
+ f_in = fopen (filename_in, "r");
+ f_out = fopen (filename_out, "w");
+ if (!f_in || !f_out) return FALSE;
+ while ((read = fread (buffer, 1, sizeof (buffer), f_in)) > 0)
+ {
+ written = fwrite (buffer, 1, read, f_out);
+ if (written < read)
+ {
+ g_warning ("%s: fwrite failed (errno = %d)",
+ G_STRFUNC, errno);
+ ret = FALSE;
+ break;
+ }
+ }
+ if (ferror (f_in))
+ {
+ g_warning ("%s: fread failed (errno = %d)",
+ G_STRFUNC, errno);
+ ret = FALSE;
+ }
+ fclose (f_in);
+ fclose (f_out);
+ return ret;
+}
+
+/**
+ * mc_account_get_params:
+ * @account: The #McAccount.
+ *
+ * Gets all the parameters for this account. The returned hash table must be
+ * freed.
+ *
+ * Return value: a #GHashTable containing all the account settings, or NULL.
+ */
+GHashTable *
+mc_account_get_params (McAccount *account)
+{
+ McProfile *profile = NULL;
+ McProtocol *protocol = NULL;
+ GSList *params, *tmp;
+ GHashTable *ret = NULL;
+
+ g_return_val_if_fail (account != NULL, NULL);
+ g_return_val_if_fail (MC_ACCOUNT_PRIV (account)->unique_name != NULL,
+ NULL);
+
+ profile = mc_account_get_profile (account);
+ if (profile == NULL)
+ {
+ g_debug ("%s: getting profile failed", G_STRFUNC);
+ goto OUT;
+ }
+
+ protocol = mc_profile_get_protocol (profile);
+ if (protocol == NULL)
+ {
+ g_debug ("%s: getting protocol failed", G_STRFUNC);
+ goto OUT;
+ }
+
+ ret = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) _g_value_free);
+
+ params = mc_protocol_get_params (protocol);
+
+ for (tmp = params; tmp != NULL; tmp = tmp->next)
+ _add_one_setting (account, (McProtocolParam *) tmp->data, ret);
+
+ mc_protocol_free_params_list (params);
+
+OUT:
+ if (protocol)
+ mc_protocol_free (protocol);
+
+ if (profile)
+ mc_profile_free (profile);
+
+ return ret;
+}
+
+/**
+ * mc_account_is_complete:
+ * @account: The #McAccount.
+ *
+ * Checks if all the mandatory parameters declared by the protocol are present
+ * in this account's settings.
+ *
+ * Return value: a gboolean.
+ */
+gboolean
+mc_account_is_complete (McAccount *account)
+{
+ McProfile *profile = NULL;
+ McProtocol *protocol = NULL;
+ GSList *params = NULL, *tmp;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+
+ /* Check if account was expunged */
+ if (MC_ACCOUNT_PRIV (account)->unique_name == NULL)
+ return FALSE;
+
+ /* Check if account was deleted */
+ if (mc_account_is_deleted (account))
+ return FALSE;
+
+ profile = mc_account_get_profile (account);
+ if (profile == NULL)
+ {
+ ret = FALSE;
+ goto OUT;
+ }
+
+ protocol = mc_profile_get_protocol (profile);
+ if (protocol == NULL)
+ {
+ ret = FALSE;
+ goto OUT;
+ }
+
+ params = mc_protocol_get_params (protocol);
+
+ for (tmp = params; tmp != NULL; tmp = tmp->next)
+ {
+ McProtocolParam *param;
+ const gchar *def;
+ GConfValue *val;
+
+ param = (McProtocolParam *) tmp->data;
+
+ if (!(param->flags & MC_PROTOCOL_PARAM_REQUIRED))
+ continue;
+
+ if (param == NULL || param->name == NULL || param->signature == NULL)
+ {
+ ret = FALSE;
+ break;
+ }
+
+ /* TODO: check this value can be mapped to the desired type */
+ def = mc_profile_get_default_setting (profile, param->name);
+ if (def)
+ {
+ continue;
+ }
+
+ val = _mc_account_gconf_get (account, param->name, TRUE);
+ if (val == NULL)
+ {
+ ret = FALSE;
+ break;
+ }
+
+ /* TODO: unduplicate this type mapping */
+ switch (param->signature[0])
+ {
+ case DBUS_TYPE_BOOLEAN:
+ if (val->type != GCONF_VALUE_BOOL)
+ ret = FALSE;
+ break;
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ if (val->type != GCONF_VALUE_INT)
+ ret = FALSE;
+ break;
+ case DBUS_TYPE_STRING:
+ if (val->type != GCONF_VALUE_STRING)
+ ret = FALSE;
+ break;
+ default:
+ ret = FALSE;
+ }
+
+ gconf_value_free (val);
+
+ if (ret == FALSE)
+ break;
+ }
+
+ mc_protocol_free_params_list (params);
+
+OUT:
+ if (profile != NULL)
+ mc_profile_free (profile);
+
+ if (protocol != NULL)
+ mc_protocol_free (protocol);
+
+ return ret;
+}
+
+/**
+ * mc_account_get_supported_presences:
+ * @account: the #McAccount.
+ *
+ * Checks what presence states are supported by this account.
+ *
+ * Returns: a zero-terminated array listing all the supported #McPresence.
+ * It must not be freed.
+ */
+const McPresence *
+mc_account_get_supported_presences (McAccount *account)
+{
+ McProfile *profile = mc_account_get_profile (account);
+ const McPresence *presences;
+
+ presences = mc_profile_get_supported_presences (profile);
+ mc_profile_free (profile);
+ return presences;
+}
+
+/*
+ * mc_account_supports_presence:
+ * @account: The #McAccount.
+ * @presence: The #McPresence.
+ *
+ * Tests whether the account supports the presence @presence.
+ *
+ * Returns: a #gboolean.
+ */
+gboolean
+mc_account_supports_presence (McAccount *account, McPresence presence)
+{
+ McProfile *profile = mc_account_get_profile (account);
+ gboolean supported;
+
+ supported = mc_profile_supports_presence (profile, presence);
+ mc_profile_free (profile);
+ return supported;
+}
+
+/**
+ * mc_account_set_avatar:
+ * @account: The #McAccount.
+ * @filename: the path of the image file to be used as avatar.
+ * @mime_type: the MIME type of the image.
+ *
+ * Set the avatar for this account. If @filename is %NULL, the avatar is
+ * cleared.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_avatar (McAccount *account, const gchar *filename,
+ const gchar *mime_type)
+{
+ gchar *data_dir, *filename_out;
+ GConfClient *client;
+ gboolean ret = TRUE;
+ gchar *key;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+
+ data_dir = get_account_data_path (MC_ACCOUNT_PRIV(account)->unique_name);
+ filename_out = g_build_filename (data_dir, MC_AVATAR_FILENAME, NULL);
+ if (!g_file_test (data_dir, G_FILE_TEST_EXISTS))
+ g_mkdir_with_parents (data_dir, 0777);
+ g_free (data_dir);
+
+ if (filename)
+ {
+ /* copy the file in the account data directory */
+ if (strcmp (filename_out, filename) != 0)
+ {
+ if (copy_file (filename, filename_out) == FALSE)
+ {
+ g_warning ("%s: copy_file failed", G_STRLOC);
+ g_free (filename_out);
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ /* create an empty file; this will cause MC to clear the current
+ * avatar */
+ FILE *f_out = fopen (filename_out, "w");
+ fclose (f_out);
+ }
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_TOKEN, FALSE);
+ ret = gconf_client_unset(client, key, NULL);
+ g_free (key);
+ if (!ret) goto error;
+
+ /* put an ID for the avatar, so that listeners of the "account-changed"
+ * signal will be able to determine whether the avatar has changed without
+ * having to load the file */
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_ID, FALSE);
+ ret = gconf_client_set_int(client, key, g_random_int(), NULL);
+ g_free (key);
+
+ if (mime_type)
+ {
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_MIME, FALSE);
+ ret = gconf_client_set_string (client, key, mime_type, NULL);
+ g_free (key);
+ }
+
+error:
+ g_object_unref (client);
+ g_free (filename_out);
+
+ return ret;
+}
+
+/**
+ * mc_account_set_avatar_token:
+ * @account: The #McAccount.
+ * @token: string holding the Telepathy token for the avatar.
+ *
+ * Set the avatar token for this account. This function is to be used only by
+ * the mission-control server.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_avatar_token (McAccount *account, const gchar *token)
+{
+ return _mc_account_gconf_set_string (account,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_TOKEN,
+ token);
+}
+
+/**
+ * mc_account_set_avatar_mime_type:
+ * @account: The #McAccount.
+ * @mime_type: string holding the mime-type of the avatar.
+ *
+ * Set the avatar mime-type for this account. This function is to be used only
+ * by the mission-control server.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_set_avatar_mime_type (McAccount *account, const gchar *mime_type)
+{
+ return _mc_account_gconf_set_string (account,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_MIME,
+ mime_type);
+}
+
+/**
+ * mc_account_get_avatar:
+ * @account: The #McAccount.
+ * @filename: address of the variable to hold the path of the image file used
+ * as avatar.
+ * @mime_type: address of the variable for the MIME type of the image.
+ * @token: address of the variable for the Telepathy token of the avatar.
+ *
+ * Get the avatar for this account. Any of the parameters for the output can be
+ * NULL, if that information is not needed.
+ *
+ * Return value: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_get_avatar (McAccount *account, gchar **filename,
+ gchar **mime_type, gchar **token)
+{
+ gchar *data_dir;
+ GConfClient *client;
+ gchar *key;
+
+ g_return_val_if_fail (account != NULL, FALSE);
+
+ if (filename)
+ {
+ data_dir =
+ get_account_data_path (MC_ACCOUNT_PRIV (account)->unique_name);
+ *filename = g_build_filename (data_dir, MC_AVATAR_FILENAME, NULL);
+ if (!g_file_test (data_dir, G_FILE_TEST_EXISTS))
+ g_mkdir_with_parents (data_dir, 0777);
+ g_free (data_dir);
+ }
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ if (token)
+ {
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_TOKEN, FALSE);
+ *token = gconf_client_get_string (client, key, NULL);
+ g_free (key);
+ }
+
+ if (mime_type)
+ {
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_MIME, FALSE);
+ *mime_type = gconf_client_get_string (client, key, NULL);
+ g_free (key);
+ }
+
+ g_object_unref (client);
+
+ return TRUE;
+}
+
+/**
+ * mc_account_get_avatar_id:
+ * @account: The #McAccount.
+ *
+ * Get the avatar ID for this account. The ID is a number that changes
+ * everytime the avatar image changes.
+ *
+ * Returns: the avatar ID.
+ */
+gint
+mc_account_get_avatar_id (McAccount *account)
+{
+ GConfClient *client;
+ gchar *key;
+ gint ret;
+
+ g_return_val_if_fail (account != NULL, 0);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != NULL, 0);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_ID, FALSE);
+ ret = gconf_client_get_int (client, key, NULL);
+ g_free (key);
+
+ g_object_unref (client);
+ return ret;
+}
+
+/**
+ * mc_account_reset_avatar_id:
+ * @account: The #McAccount.
+ *
+ * Calculates a new avatar ID for this account. This function is to be called
+ * when the avatar image file has been changed by a direct modification of its
+ * binary content.
+ *
+ * Returns: %TRUE, or %FALSE if some error occurred.
+ */
+gboolean
+mc_account_reset_avatar_id (McAccount *account)
+{
+ GConfClient *client;
+ gchar *key;
+ gboolean ok;
+
+ g_return_val_if_fail (account != FALSE, 0);
+
+ client = gconf_client_get_default ();
+ g_return_val_if_fail (client != FALSE, 0);
+
+ key = _mc_account_path (MC_ACCOUNT_PRIV (account)->unique_name,
+ MC_ACCOUNTS_GCONF_KEY_AVATAR_ID, FALSE);
+ ok = gconf_client_set_int (client, key, g_random_int(), NULL);
+ g_free (key);
+
+ g_object_unref (client);
+ return ok;
+}
+
diff --git a/libmissioncontrol/mc-account.h b/libmissioncontrol/mc-account.h
new file mode 100644
index 00000000..a839d577
--- /dev/null
+++ b/libmissioncontrol/mc-account.h
@@ -0,0 +1,182 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_ACCOUNT_H__
+#define __MC_ACCOUNT_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MC_TYPE_ACCOUNT mc_account_get_type()
+
+#define MC_ACCOUNT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MC_TYPE_ACCOUNT, McAccount))
+
+#define MC_ACCOUNT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MC_TYPE_ACCOUNT, McAccountwClass))
+
+#define MC_IS_ACCOUNT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MC_TYPE_ACCOUNT))
+
+#define MC_IS_ACCOUNT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MC_TYPE_ACCOUNT))
+
+#define MC_ACCOUNT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MC_TYPE_ACCOUNT, McAccountwClass))
+
+typedef struct {
+ GObject parent;
+ gpointer priv;
+} McAccount;
+
+typedef struct {
+ GObjectClass parent_class;
+} McAccountClass;
+
+GType mc_account_get_type (void);
+
+McAccount* mc_account_new (void);
+
+typedef enum
+{
+ MC_ACCOUNT_SETTING_ABSENT = 0,
+ MC_ACCOUNT_SETTING_FROM_ACCOUNT,
+ MC_ACCOUNT_SETTING_FROM_PROFILE,
+ MC_ACCOUNT_SETTING_FROM_PROXY,
+} McAccountSettingState;
+
+#include <libmissioncontrol/mc-profile.h>
+
+/* returns NULL if unique name does not exist */
+McAccount *mc_account_lookup (const gchar *unique_name);
+McAccount *mc_account_lookup_with_profile (McProfile *profile,
+ const gchar *account);
+McAccount *mc_account_lookup_with_vcard_field (const gchar *vcard_field,
+ const gchar *account);
+void mc_account_free (McAccount* account);
+void mc_account_clear_cache (void);
+
+/* returns newly-created account, enabled by default */
+McAccount *mc_account_create (McProfile *profile);
+
+/* this function only deletes the account from database,
+ * the account struct itself must be freed separately */
+gboolean mc_account_delete (McAccount *account);
+
+/* lists returned by these functions should be freed with
+ * mc_accounts_list_free */
+GList *mc_accounts_list (void);
+GList *mc_accounts_list_by_enabled (gboolean enabled);
+GList *mc_accounts_list_by_profile (McProfile *profile);
+GList *mc_accounts_list_by_vcard_field (const gchar *vcard_field);
+void mc_accounts_list_free (GList *list);
+
+/* filter a list of accounts according to whether a function returns TRUE,
+ * freeing the list and any accounts which are filtered out, and returning a
+ * new list which must be freed with mc_accounts_list_free. */
+typedef gboolean (*McAccountFilter) (McAccount *account, gpointer data);
+GList *mc_accounts_filter (GList *accounts,
+ McAccountFilter filter,
+ gpointer data);
+
+/* a unique identifier string for this account */
+const gchar *mc_account_get_unique_name (McAccount *account);
+
+/* get profile */
+McProfile *mc_account_get_profile (McAccount *account);
+
+/* human-readable name */
+const gchar *mc_account_get_display_name (McAccount *account);
+gboolean mc_account_set_display_name (McAccount *account,
+ const gchar *name);
+
+/* normalized name */
+const gchar *mc_account_get_normalized_name (McAccount *account);
+gboolean mc_account_set_normalized_name (McAccount *account,
+ const gchar *name);
+
+/* whether account is enabled or disabled */
+gboolean mc_account_is_enabled (McAccount *account);
+gboolean mc_account_set_enabled (McAccount *account,
+ const gboolean enabled);
+
+/* the following methods retrieve a parameter from the account or the
+ * default from the profile if the account does not set the value */
+McAccountSettingState mc_account_get_param_boolean (McAccount *account,
+ const gchar *name,
+ gboolean *value);
+McAccountSettingState mc_account_get_param_int (McAccount *account,
+ const gchar *name,
+ gint *value);
+McAccountSettingState mc_account_get_param_string (McAccount *account,
+ const gchar *name,
+ gchar **value);
+
+/* for every parameter (both optional and mandatory) defined by the
+ * protocol, get a hash table of the params from the account or
+ * the default profile. each setting is stored in a GValue. */
+GHashTable *mc_account_get_params (McAccount *account);
+
+/* Set functions. Returns true if success, else false is returned */
+gboolean mc_account_set_param_boolean (McAccount *account,
+ const gchar *name,
+ gboolean value);
+gboolean mc_account_set_param_int (McAccount *account,
+ const gchar *name,
+ gint value);
+gboolean mc_account_set_param_string (McAccount *account,
+ const gchar *name,
+ const gchar *value);
+
+gboolean mc_account_unset_param (McAccount *account, const gchar *name);
+
+/* returns TRUE if the account information, along with the profile defaults
+ * has all mandatory fields (declared by the protocol) set */
+gboolean mc_account_is_complete (McAccount *account);
+
+const McPresence *mc_account_get_supported_presences (McAccount *account);
+gboolean mc_account_supports_presence (McAccount *account,
+ McPresence presence);
+
+gboolean mc_account_set_avatar (McAccount *account, const gchar *filename,
+ const gchar *mime_type);
+gboolean mc_account_get_avatar (McAccount *account, gchar **filename,
+ gchar **mime_type, gchar **token);
+
+gboolean mc_account_set_avatar_token (McAccount *account, const gchar *token);
+gboolean mc_account_set_avatar_mime_type (McAccount *account,
+ const gchar *mime_type);
+
+gint mc_account_get_avatar_id (McAccount *account);
+gboolean mc_account_reset_avatar_id (McAccount *account);
+
+G_END_DECLS
+
+#endif /* __MC_ACCOUNT_H__ */
diff --git a/libmissioncontrol/mc-manager-priv.h b/libmissioncontrol/mc-manager-priv.h
new file mode 100644
index 00000000..4950699d
--- /dev/null
+++ b/libmissioncontrol/mc-manager-priv.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_MANAGER_PRIV_H__
+#define __MC_MANAGER_PRIV_H__
+
+#include "mc-protocol.h"
+
+McProtocol *
+_mc_manager_protocol_lookup (McManager *manager, const gchar *name);
+
+#endif /* __MC_MANAGER_PRIV_H__ */
diff --git a/libmissioncontrol/mc-manager.c b/libmissioncontrol/mc-manager.c
new file mode 100644
index 00000000..4e9e4440
--- /dev/null
+++ b/libmissioncontrol/mc-manager.c
@@ -0,0 +1,388 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "mc-protocol.h"
+#include "mc-protocol-priv.h"
+
+#include "mc-manager.h"
+#include "mc-manager-priv.h"
+
+#define MANAGER_PATH "/usr/share/telepathy/managers"
+#define MANAGER_SUFFIX ".manager"
+#define MANAGER_SUFFIX_LEN 8
+
+#define MC_MANAGER_PRIV(manager) ((McManagerPrivate *)manager->priv)
+
+G_DEFINE_TYPE (McManager, mc_manager, G_TYPE_OBJECT);
+
+static GHashTable *manager_cache = NULL;
+
+typedef struct {
+ gchar *unique_name;
+ gchar *bus_name;
+ gchar *object_path;
+ time_t mtime;
+ GSList *protocols;
+} McManagerPrivate;
+
+static void
+mc_manager_finalize (GObject *object)
+{
+ McManager *manager = MC_MANAGER(object);
+ McManagerPrivate *priv = MC_MANAGER_PRIV (manager);
+ GSList *i;
+
+ g_free (priv->unique_name);
+ g_free (priv->bus_name);
+ g_free (priv->object_path);
+
+ for (i = priv->protocols; NULL != i; i = i->next)
+ g_object_unref (G_OBJECT (i->data));
+
+ g_slist_free (priv->protocols);
+}
+
+static void
+mc_manager_class_init (McManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McManagerPrivate));
+ object_class->finalize = mc_manager_finalize;
+}
+
+static void
+mc_manager_init (McManager *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ MC_TYPE_MANAGER, McManagerPrivate);
+}
+
+static McManager *
+mc_manager_new (gchar *unique_name, gchar *bus_name, gchar *object_path,
+ GSList *protocols)
+{
+ McManager *new = g_object_new (MC_TYPE_MANAGER, NULL);
+ McManagerPrivate *priv = MC_MANAGER_PRIV (new);
+
+ priv->unique_name = unique_name;
+ priv->bus_name = bus_name;
+ priv->object_path = object_path;
+ priv->protocols = protocols;
+
+ return new;
+}
+
+static const gchar *
+_mc_manager_path (void)
+{
+ const gchar *ret = NULL;
+
+ if (ret == NULL)
+ {
+ ret = g_getenv ("MC_MANAGER_DIR");
+ if (ret == NULL)
+ ret = MANAGER_PATH;
+ }
+
+ return ret;
+}
+
+static gchar *
+_mc_manager_filename (const gchar *unique_name)
+{
+ return g_strconcat (_mc_manager_path (), G_DIR_SEPARATOR_S,
+ unique_name, MANAGER_SUFFIX, NULL);
+}
+
+#define PREFIX_PROTOCOL "Protocol "
+#define PREFIX_PROTOCOL_LEN 9
+#define PREFIX_PROTOCOL_OLD "Proto "
+#define PREFIX_PROTOCOL_OLD_LEN 6
+
+static GSList *
+_keyfile_get_protocols (GKeyFile *keyfile, const gchar *manager)
+{
+ GSList *protocols = NULL;
+ gchar **groups = NULL;
+ gchar **i;
+
+ groups = g_key_file_get_groups (keyfile, NULL);
+
+ for (i = groups; NULL != *i; i++)
+ {
+ const gchar *name = NULL;
+
+ if (0 == strncmp (*i, PREFIX_PROTOCOL, PREFIX_PROTOCOL_LEN))
+ name = *i + PREFIX_PROTOCOL_LEN;
+ else if (0 == strncmp (*i, PREFIX_PROTOCOL_OLD, PREFIX_PROTOCOL_OLD_LEN))
+ name = *i + PREFIX_PROTOCOL_OLD_LEN;
+
+ if (NULL != name)
+ {
+ McProtocol *protocol = _mc_protocol_from_keyfile (keyfile,
+ manager, *i, name);
+
+ if (protocol)
+ protocols = g_slist_prepend (protocols, protocol);
+ }
+ }
+
+ g_strfreev (groups);
+ return protocols;
+}
+
+static McManager *
+_mc_manager_from_file (const gchar *unique_name, const gchar *filename)
+{
+ GError *error;
+ GKeyFile *keyfile;
+ gchar *bus_name = NULL;
+ gchar *object_path = NULL;
+ GSList *protocols = NULL;
+
+ keyfile = g_key_file_new ();
+
+ if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
+ {
+ g_debug ("%s: loading %s failed: %s", G_STRFUNC, filename, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ bus_name = g_key_file_get_string (
+ keyfile, "ConnectionManager", "BusName", NULL);
+ object_path = g_key_file_get_string (
+ keyfile, "ConnectionManager", "ObjectPath", NULL);
+
+ if (!bus_name || !object_path)
+ {
+ g_debug ("%s: failed to get name, bus name and object path from file",
+ G_STRFUNC);
+ g_free (bus_name);
+ g_free (object_path);
+ return NULL;
+ }
+
+ protocols = _keyfile_get_protocols (keyfile, unique_name);
+ g_key_file_free (keyfile);
+
+ return mc_manager_new (g_strdup (unique_name), bus_name, object_path,
+ protocols);
+}
+
+static time_t
+_mc_manager_get_mtime (McManager *manager)
+{
+ McManagerPrivate *priv = MC_MANAGER_PRIV (manager);
+ return priv->mtime;
+}
+
+/**
+ * mc_manager_lookup:
+ * @unique_name: the unique name.
+ *
+ * Looks up for the #McManager having the given unique name.
+ * The returned object's reference count is incremented.
+ *
+ * Returns: the #McManager, or NULL if not found.
+ */
+McManager *
+mc_manager_lookup (const gchar *unique_name)
+{
+ McManager *manager = NULL;
+ gchar *filename;
+ struct stat buf;
+
+ g_return_val_if_fail (unique_name != NULL, NULL);
+ g_return_val_if_fail (*unique_name != '\0', NULL);
+
+ filename = _mc_manager_filename (unique_name);
+
+ if (0 != g_stat (filename, &buf))
+ goto OUT;
+
+ if (NULL == manager_cache)
+ manager_cache = g_hash_table_new_full (
+ g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ manager = g_hash_table_lookup (manager_cache, unique_name);
+
+ if (NULL != manager && _mc_manager_get_mtime (manager) >= buf.st_mtime)
+ {
+ g_object_ref (manager);
+ goto OUT;
+ }
+
+ manager = _mc_manager_from_file (unique_name, filename);
+
+ if (NULL != manager)
+ {
+ McManagerPrivate *priv;
+ priv = MC_MANAGER_PRIV (manager);
+ priv->mtime = buf.st_mtime;
+ g_hash_table_replace (manager_cache, g_strdup (unique_name), manager);
+ g_object_ref (manager);
+ }
+
+OUT:
+ g_free (filename);
+ return manager;
+}
+
+/**
+ * mc_manager_free:
+ * @id: the #McManager.
+ *
+ * Frees (unrefs) the manager.
+ */
+void
+mc_manager_free (McManager *id)
+{
+ g_return_if_fail (id != NULL);
+
+ g_object_unref (id);
+}
+
+/**
+ * mc_manager_clear_cache:
+ *
+ * Clears the managers cache.
+ */
+void
+mc_manager_clear_cache(void)
+{
+ if (NULL == manager_cache)
+ return;
+
+ g_hash_table_destroy(manager_cache);
+ manager_cache = NULL;
+}
+
+/**
+ * mc_managers_list:
+ *
+ * Lists all configured managers. <emphasis>Currently this function returns
+ * only the "gabble" manager</emphasis>.
+ *
+ * Returns: a #GList of the managers, to be freed with #mc_managers_free_list.
+ */
+GList *
+mc_managers_list (void)
+{
+ return g_list_prepend (NULL, mc_manager_lookup ("gabble"));
+}
+
+/**
+ * mc_managers_free_list:
+ * @list: a #GList of #McManager.
+ *
+ * Frees a list of managers.
+ */
+void
+mc_managers_free_list (GList *list)
+{
+ GList *tmp;
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next)
+ mc_manager_free ((McManager *) tmp->data);
+
+ g_list_free (list);
+}
+
+/**
+ * mc_manager_get_unique_name:
+ * @id: the #McManager.
+ *
+ * Gets the unique name of the manager.
+ *
+ * Returns: the unique name, as a string (not to be freed).
+ */
+const gchar *
+mc_manager_get_unique_name (McManager *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return MC_MANAGER_PRIV (id)->unique_name;
+}
+
+/**
+ * mc_manager_get_bus_name:
+ * @id: the #McManager.
+ *
+ * Gets the D-Bus bus name of the manager.
+ *
+ * Returns: the bus name, as a string (not to be freed).
+ */
+const gchar *
+mc_manager_get_bus_name (McManager *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return MC_MANAGER_PRIV (id)->bus_name;
+}
+
+/**
+ * mc_manager_get_object_path:
+ * @id: the #McManager.
+ *
+ * Gets the D-Bus object path of the manager.
+ *
+ * Returns: the object path, as a string (not to be freed).
+ */
+const gchar *
+mc_manager_get_object_path (McManager *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return MC_MANAGER_PRIV (id)->object_path;
+}
+
+McProtocol *
+_mc_manager_protocol_lookup (McManager *manager, const gchar *name)
+{
+ GSList *i;
+
+ g_return_val_if_fail (manager != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (*name != '\0', NULL);
+
+ for (i = MC_MANAGER_PRIV (manager)->protocols; NULL != i; i++)
+ {
+ McProtocol *protocol = (McProtocol *) i->data;
+
+ if (0 == strcmp (name, mc_protocol_get_name (protocol)))
+ {
+ g_object_ref (protocol);
+ return protocol;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/libmissioncontrol/mc-manager.h b/libmissioncontrol/mc-manager.h
new file mode 100644
index 00000000..b7995bca
--- /dev/null
+++ b/libmissioncontrol/mc-manager.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_MANAGER_H__
+#define __MC_MANAGER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MC_TYPE_MANAGER mc_manager_get_type()
+
+#define MC_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MC_TYPE_MANAGER, McManager))
+
+#define MC_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MC_TYPE_MANAGER, McManagerClass))
+
+#define MC_IS_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MC_TYPE_MANAGER))
+
+#define MC_IS_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MC_TYPE_MANAGER))
+
+#define MC_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MC_TYPE_MANAGER, McManagerClass))
+
+typedef struct {
+ GObject parent;
+ gpointer priv;
+} McManager;
+
+typedef struct {
+ GObjectClass parent_class;
+} McManagerClass;
+
+GType mc_manager_get_type (void);
+
+McManager *mc_manager_lookup (const gchar *unique_name);
+void mc_manager_free (McManager *id);
+void mc_manager_clear_cache (void);
+
+/* get all managers; returns a list of McManager *s */
+GList *mc_managers_list (void);
+void mc_managers_free_list (GList *list);
+
+const gchar *mc_manager_get_unique_name (McManager *id);
+const gchar *mc_manager_get_bus_name (McManager *id);
+const gchar *mc_manager_get_object_path (McManager *id);
+
+G_END_DECLS
+
+#endif /* __MC_MANAGER_H__ */
diff --git a/libmissioncontrol/mc-profile.c b/libmissioncontrol/mc-profile.c
new file mode 100644
index 00000000..b6be4acf
--- /dev/null
+++ b/libmissioncontrol/mc-profile.c
@@ -0,0 +1,837 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <libintl.h>
+
+#include "mc-profile.h"
+#include "mc-enum-types.h"
+#include <config.h>
+
+#define PROFILE_SUFFIX ".profile"
+#define PROFILE_SUFFIX_LEN 8
+#define PROFILE_GROUP "Profile"
+
+#define MC_PROFILE_PRIV(profile) ((McProfilePrivate *)profile->priv)
+
+G_DEFINE_TYPE (McProfile, mc_profile, G_TYPE_OBJECT);
+
+static GHashTable *profile_cache = NULL;
+
+const GDebugKey capabilities[] = {
+ { "chat-p2p", MC_PROFILE_CAPABILITY_CHAT_P2P },
+ { "chat-room", MC_PROFILE_CAPABILITY_CHAT_ROOM },
+ { "chat-room-list", MC_PROFILE_CAPABILITY_CHAT_ROOM_LIST },
+ { "voice-p2p", MC_PROFILE_CAPABILITY_VOICE_P2P },
+ { "contact-search", MC_PROFILE_CAPABILITY_CONTACT_SEARCH },
+ { "split-account", MC_PROFILE_CAPABILITY_SPLIT_ACCOUNT },
+ { "registration-ui", MC_PROFILE_CAPABILITY_REGISTRATION_UI },
+ { "supports-avatars", MC_PROFILE_CAPABILITY_SUPPORTS_AVATARS },
+};
+
+typedef struct {
+ gchar *unique_name;
+ gboolean loaded;
+ gchar *configuration_ui;
+ gchar *display_name;
+ gchar *icon_name;
+ gchar *branding_icon_name;
+ gchar *manager;
+ gchar *protocol;
+ gchar *vcard_field;
+ gchar *default_account_domain;
+ gboolean vcard_default;
+ McProfileCapabilityFlags capabilities;
+ GHashTable *default_settings;
+ GArray *supported_presences;
+ time_t mtime;
+} McProfilePrivate;
+
+static void
+mc_profile_init (McProfile *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ MC_TYPE_PROFILE, McProfilePrivate);
+}
+
+static void
+mc_profile_finalize (GObject *object)
+{
+ McProfile *self = MC_PROFILE(object);
+ McProfilePrivate *priv;
+ g_return_if_fail (self != NULL);
+
+ priv = MC_PROFILE_PRIV (self);
+ g_free (priv->unique_name);
+ g_free (priv->configuration_ui);
+ g_free (priv->display_name);
+ g_free (priv->icon_name);
+ g_free (priv->branding_icon_name);
+ g_free (priv->manager);
+ g_free (priv->protocol);
+ g_free (priv->vcard_field);
+ g_free (priv->default_account_domain);
+ g_hash_table_destroy (priv->default_settings);
+ g_array_free (priv->supported_presences, TRUE);
+}
+
+static void
+mc_profile_class_init (McProfileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McProfilePrivate));
+ object_class->finalize = mc_profile_finalize;
+}
+
+/**
+ * mc_profile_clear_cache:
+ *
+ * Clears the profiles cache.
+ */
+void
+mc_profile_clear_cache(void)
+{
+ if (NULL == profile_cache)
+ return;
+
+ g_hash_table_destroy(profile_cache);
+ profile_cache = NULL;
+}
+
+static const gchar * _mc_profile_path (void);
+static gchar * _mc_profile_filename (const gchar *name);
+
+static time_t
+_mc_profile_mtime (McProfile *profile)
+{
+ McProfilePrivate *priv = MC_PROFILE_PRIV (profile);
+ return priv->mtime;
+}
+
+static McProfile *
+_mc_profile_new (const gchar *unique_name)
+{
+ McProfile *profile = NULL;
+ McProfilePrivate *priv;
+ struct stat buf;
+ gchar *filename = _mc_profile_filename (unique_name);
+
+ if (0 != g_stat (filename, &buf))
+ goto OUT;
+
+ if (NULL == profile_cache)
+ profile_cache = g_hash_table_new_full (
+ g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ profile = g_hash_table_lookup (profile_cache, unique_name);
+
+ if (NULL != profile && _mc_profile_mtime (profile) >= buf.st_mtime)
+ {
+ g_object_ref (profile);
+ goto OUT;
+ }
+
+ profile = (McProfile *) g_object_new (MC_TYPE_PROFILE, NULL);
+ priv = MC_PROFILE_PRIV (profile);
+ priv->unique_name = g_strdup (unique_name);
+ priv->mtime = buf.st_mtime;
+ g_hash_table_replace (profile_cache, g_strdup (unique_name), profile);
+ g_object_ref (profile);
+
+OUT:
+ g_free (filename);
+ return profile;
+}
+
+static const gchar *
+_mc_profile_path (void)
+{
+ const gchar *ret = NULL;
+
+ if (ret == NULL)
+ {
+ ret = g_getenv ("MC_PROFILE_DIR");
+ if (ret == NULL)
+ ret = PROFILES_DIR;
+ }
+
+ return ret;
+}
+
+static gchar *
+_mc_profile_filename (const gchar *name)
+{
+ return g_strconcat (_mc_profile_path (), G_DIR_SEPARATOR_S,
+ name, PROFILE_SUFFIX, NULL);
+}
+
+static gboolean
+_mc_profile_load (McProfile *profile)
+{
+ gchar *filename;
+ GKeyFile *keyfile;
+ GError *error = NULL;
+ gchar *caps, *localization_domain;
+ gchar **keys, **tmp;
+ McProfilePrivate *priv;
+ gchar **presences_str;
+ GEnumClass *presences_class;
+ gsize length;
+ gint i;
+
+ priv = MC_PROFILE_PRIV (profile);
+
+ if (priv->loaded)
+ return TRUE;
+
+ filename = _mc_profile_filename (priv->unique_name);
+
+ keyfile = g_key_file_new ();
+ if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
+ {
+ g_debug ("%s: loading %s failed: %s", G_STRFUNC, filename, error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ priv->configuration_ui = g_key_file_get_string (keyfile, PROFILE_GROUP, "ConfigurationUI", NULL);
+ priv->display_name = g_key_file_get_string (keyfile, PROFILE_GROUP, "DisplayName", NULL);
+ priv->icon_name = g_key_file_get_string (keyfile, PROFILE_GROUP, "IconName", NULL);
+ priv->branding_icon_name = g_key_file_get_string (keyfile, PROFILE_GROUP, "BrandingIconName", NULL);
+ priv->manager = g_key_file_get_string (keyfile, PROFILE_GROUP, "Manager", NULL);
+ priv->protocol = g_key_file_get_string (keyfile, PROFILE_GROUP, "Protocol", NULL);
+ priv->vcard_field = g_key_file_get_string (keyfile, PROFILE_GROUP, "VCardField", NULL);
+ priv->vcard_default = g_key_file_get_boolean (keyfile, PROFILE_GROUP, "VCardDefault", NULL);
+ priv->default_account_domain = g_key_file_get_string (keyfile, PROFILE_GROUP, "DefaultAccountDomain", NULL);
+ localization_domain = g_key_file_get_string (keyfile, PROFILE_GROUP, "LocalizationDomain", NULL);
+ if (localization_domain)
+ {
+ gchar *display_name;
+
+ display_name = g_strdup (dgettext (localization_domain,
+ priv->display_name));
+ g_free (priv->display_name);
+ priv->display_name = display_name;
+ g_free (localization_domain);
+ }
+
+ g_key_file_set_list_separator (keyfile, ',');
+ presences_str = g_key_file_get_string_list (keyfile, PROFILE_GROUP,
+ "SupportedPresences", &length,
+ NULL);
+ if (!presences_str) length = 0;
+ presences_class = g_type_class_ref (MC_TYPE_PRESENCE);
+ priv->supported_presences = g_array_sized_new (TRUE, FALSE,
+ sizeof (McPresence), length);
+ for (i = 0; i < length; i++)
+ {
+ McPresence presence;
+ GEnumValue *value;
+
+ value = g_enum_get_value_by_nick (presences_class,
+ presences_str[i]);
+ if (!value)
+ {
+ g_warning ("Unrecognized presence `%s'", presences_str[i]);
+ continue;
+ }
+ presence = value->value;
+ g_array_append_val (priv->supported_presences, presence);
+ }
+ g_type_class_unref (presences_class);
+ g_strfreev (presences_str);
+
+ /* :D */
+ caps = g_key_file_get_string (keyfile, PROFILE_GROUP, "Capabilities", NULL);
+ g_strdelimit (caps, " ,;", ':');
+ priv->capabilities = g_parse_debug_string (caps, capabilities, sizeof (capabilities) / sizeof (GDebugKey));
+ g_free (caps);
+
+ priv->default_settings = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+ keys = g_key_file_get_keys (keyfile, PROFILE_GROUP, 0, NULL);
+ for (tmp = keys; *tmp != NULL; tmp++)
+ {
+ gchar *key = *tmp;
+ if (0 == g_ascii_strncasecmp ("Default-", key, 8))
+ {
+ gchar *k, *v;
+ k = g_strdup (key+8);
+ v = g_key_file_get_string (keyfile, PROFILE_GROUP, key, NULL);
+ g_hash_table_insert (MC_PROFILE_PRIV (profile)->default_settings, k, v);
+ }
+ }
+ g_strfreev (keys);
+
+ g_key_file_free (keyfile);
+ g_free (filename);
+
+ priv->loaded = TRUE;
+ return TRUE;
+}
+
+/**
+ * mc_profile_lookup:
+ * @unique_name: The unique name of the profile.
+ *
+ * Get the profile whose unique name is the one specified. If no profile with
+ * that name exists, a new one is created. The returned object's reference
+ * count is incremented.
+ *
+ * Return value: The #McProfile.
+ */
+McProfile *
+mc_profile_lookup (const gchar *unique_name)
+{
+ g_return_val_if_fail (unique_name != NULL, NULL);
+ g_return_val_if_fail (*unique_name != '\0', NULL);
+
+ return _mc_profile_new (unique_name);
+}
+
+/**
+ * mc_profile_lookup_default_for_vcard_field:
+ * @vcard_field: The vcard field.
+ *
+ * Get the profile whose vcard field is the one specified.
+ * The returned object's reference count is incremented.
+ *
+ * Return value: The #McProfile.
+ */
+McProfile *
+mc_profile_lookup_default_for_vcard_field (const gchar *vcard_field)
+{
+ McProfile *ret = NULL;
+ GList *list, *tmp;
+
+ g_return_val_if_fail (vcard_field != NULL, NULL);
+ g_return_val_if_fail (*vcard_field != '\0', NULL);
+
+ list = mc_profiles_list ();
+
+ for (tmp = list;
+ tmp != NULL;
+ tmp = tmp->next)
+ {
+ McProfile *cur = (McProfile *) tmp->data;
+ McProfilePrivate *priv = MC_PROFILE_PRIV (cur);
+
+ /* free the profile if we've found the desired value,
+ * or we're unable to load this one */
+ if (ret != NULL ||
+ !_mc_profile_load (cur))
+ {
+ mc_profile_free (cur);
+ continue;
+ }
+
+ /* store the profile if it's the desired one,
+ * free it otherwise */
+ if (priv->vcard_default &&
+ 0 == strcmp (priv->vcard_field, vcard_field))
+ {
+ ret = cur;
+ break;
+ }
+ else
+ {
+ mc_profile_free (cur);
+ }
+ }
+
+ g_list_free (list);
+
+ return ret;
+}
+
+/**
+ * mc_profile_free:
+ * @id: The #McProfile.
+ *
+ * Frees (unref) the given profile.
+ */
+void
+mc_profile_free (McProfile *id)
+{
+ g_object_unref (id);
+}
+
+/**
+ * mc_profiles_list:
+ *
+ * Lists all configured profiles.
+ *
+ * Returns: a #GList of the profiles (must be freed with #mc_profiles_free_list).
+ */
+GList *
+mc_profiles_list (void)
+{
+ GDir *dir;
+ GError *error = NULL;
+ GList *ret = NULL;
+ const gchar *filename;
+
+ dir = g_dir_open(_mc_profile_path (), 0, &error);
+ if (!dir)
+ {
+ g_warning ("%s: unable to open directory %s: %s",
+ G_STRFUNC, _mc_profile_path (), error->message);
+
+ g_error_free (error);
+
+ return NULL;
+ }
+
+ while ((filename = g_dir_read_name(dir)) != NULL)
+ {
+ gchar *unique_name;
+ McProfile *profile;
+
+ if (!g_str_has_suffix (filename, PROFILE_SUFFIX))
+ continue;
+
+ unique_name = g_strndup (filename, strlen(filename) - PROFILE_SUFFIX_LEN);
+ profile = _mc_profile_new (unique_name);
+ g_free (unique_name);
+
+ ret = g_list_prepend (ret, profile);
+ }
+
+ g_dir_close (dir);
+
+ return ret;
+}
+
+/**
+ * mc_profiles_list_by_vcard_field:
+ * @vcard_field: The vcard field.
+ *
+ * Lists all configured profiles with the given vcard field..
+ *
+ * Returns: a #GList of the profiles (must be freed with #mc_profiles_free_list).
+ */
+GList *
+mc_profiles_list_by_vcard_field (const gchar *vcard_field)
+{
+ GList *all, *tmp, *ret;
+
+ g_return_val_if_fail (vcard_field != NULL, NULL);
+ g_return_val_if_fail (*vcard_field != '\0', NULL);
+
+ all = mc_profiles_list ();
+ ret = NULL;
+
+ for (tmp = all;
+ tmp != NULL;
+ tmp = tmp->next)
+ {
+ McProfile *cur = (McProfile *) tmp->data;
+ McProfilePrivate *priv = MC_PROFILE_PRIV (cur);
+
+ if (!_mc_profile_load (cur))
+ {
+ mc_profile_free (cur);
+ continue;
+ }
+
+ if (priv->vcard_field && 0 == strcmp (vcard_field, priv->vcard_field))
+ {
+ ret = g_list_prepend (ret, cur);
+ }
+ else
+ {
+ mc_profile_free (cur);
+ }
+ }
+
+ g_list_free (all);
+
+ return ret;
+}
+
+/**
+ * mc_profiles_free_list:
+ * @list: The #GList of #McProfile.
+ *
+ * Frees a list of profiles.
+ */
+void
+mc_profiles_free_list (GList *list)
+{
+ GList *tmp;
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next)
+ {
+ McProfile *p = tmp->data;
+ mc_profile_free (p);
+ }
+
+ g_list_free (list);
+}
+
+/**
+ * mc_profile_get_unique_name:
+ * @id: The #McProfile.
+ *
+ * Get the unique name of the profile.
+ *
+ * Returns: a string representing the unique name (must not be freed).
+ */
+const gchar *
+mc_profile_get_unique_name (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV(id)->unique_name;
+}
+
+/**
+ * mc_profile_get_configuration_ui:
+ * @id: The #McProfile.
+ *
+ * Get the configuration ui of the profile.
+ *
+ * Returns: a string representing the configuration ui (must not be freed).
+ */
+const gchar *
+mc_profile_get_configuration_ui (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV (id)->configuration_ui;
+}
+
+/**
+ * mc_profile_get_display_name:
+ * @id: The #McProfile.
+ *
+ * Get the display name of the profile.
+ *
+ * Returns: a string representing the display name (must not be freed).
+ */
+const gchar *
+mc_profile_get_display_name (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV (id)->display_name;
+}
+
+/**
+ * mc_profile_get_icon_name:
+ * @id: The #McProfile.
+ *
+ * Get the icon name of the profile.
+ *
+ * Returns: a string representing the icon name (must not be freed).
+ */
+const gchar *
+mc_profile_get_icon_name (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV (id)->icon_name;
+}
+
+/**
+ * mc_profile_get_branding_icon_name:
+ * @id: The #McProfile.
+ *
+ * Get the branding icon name of the profile.
+ *
+ * Returns: a string representing the branding icon name (must not be freed).
+ */
+const gchar *
+mc_profile_get_branding_icon_name (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV (id)->branding_icon_name;
+}
+
+/**
+ * mc_profile_get_supported_presences:
+ * @id: The #McProfile.
+ *
+ * Checks what presence states are supported by this profile.
+ *
+ * Returns: a zero-terminated array listing all the supported #McPresence.
+ * It must not be freed.
+ */
+const McPresence *
+mc_profile_get_supported_presences (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return (McPresence *)(MC_PROFILE_PRIV (id)->supported_presences->data);
+}
+
+/*
+ * mc_profile_supports_presence:
+ * @id: The #McProfile.
+ * @presence: The #McPresence.
+ *
+ * Tests whether the profile supports the presence @presence.
+ *
+ * Returns: a #gboolean.
+ */
+gboolean
+mc_profile_supports_presence (McProfile *id, McPresence presence)
+{
+ const McPresence *presences;
+
+ presences = mc_profile_get_supported_presences (id);
+ if (!presences) return FALSE;
+
+ while (*presences)
+ {
+ if (*presences == presence)
+ return TRUE;
+ presences++;
+ }
+ return FALSE;
+}
+
+/**
+ * mc_profile_get_protocol:
+ * @id: The #McProfile.
+ *
+ * gets the protocol in use for this profile.
+ *
+ * Returns: a #McProtocol, or NULL if some error occurs.
+ */
+McProtocol *
+mc_profile_get_protocol (McProfile *id)
+{
+ McManager *manager;
+ McProtocol *protocol;
+ McProfilePrivate *priv = MC_PROFILE_PRIV (id);
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ manager = mc_manager_lookup (priv->manager);
+ g_return_val_if_fail (manager != NULL, NULL);
+
+ protocol = mc_protocol_lookup (manager, priv->protocol);
+ mc_manager_free (manager);
+
+ g_return_val_if_fail (protocol != NULL, NULL);
+ return protocol;
+}
+
+/**
+ * mc_profile_get_protocol_name:
+ * @id: The #McProfile.
+ *
+ * Get the protocol name of the profile.
+ *
+ * Returns: a string representing the protocol name (must not be freed).
+ */
+const gchar *
+mc_profile_get_protocol_name (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV (id)->protocol;
+}
+
+/**
+ * mc_profile_get_vcard_field:
+ * @id: The #McProfile.
+ *
+ * Get the vcard field of the profile.
+ *
+ * Returns: a string representing the vcard field (must not be freed).
+ */
+const gchar *
+mc_profile_get_vcard_field (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ return MC_PROFILE_PRIV (id)->vcard_field;
+}
+
+/**
+ * mc_profile_get_default_account_domain:
+ * @id: The #McProfile.
+ *
+ * Get the default account domain of the profile.
+ *
+ * Returns: a string representing the default account domain (must not be
+ * freed).
+ */
+const gchar *
+mc_profile_get_default_account_domain (McProfile *id)
+{
+ McProfilePrivate *priv = MC_PROFILE_PRIV (id);
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+ g_return_val_if_fail (
+ priv->capabilities & MC_PROFILE_CAPABILITY_SPLIT_ACCOUNT, NULL);
+
+ return priv->default_account_domain;
+}
+
+/**
+ * mc_profile_is_default_for_vcard_field:
+ * @id: The #McProfile.
+ *
+ * Checks if this is the default profile for the given vcard field.
+ *
+ * Returns: a gboolean.
+ */
+gboolean
+mc_profile_is_default_for_vcard_field (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, FALSE);
+
+ return MC_PROFILE_PRIV (id)->vcard_default;
+}
+
+/**
+ * mc_profile_get_capabilities:
+ * @id: The #McProfile.
+ *
+ * Gets the capabilities of this profile.
+ *
+ * Returns: a combination of #McProfileCapabilityFlags.
+ */
+McProfileCapabilityFlags
+mc_profile_get_capabilities (McProfile *id)
+{
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, 0);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, 0);
+
+ return MC_PROFILE_PRIV (id)->capabilities;
+}
+
+/**
+ * mc_profile_get_default_setting:
+ * @id: The #McProfile.
+ * @setting: The setting for which default value has to be retrieved.
+ *
+ * Get the default value of a setting of the profile.
+ *
+ * Returns: a string representing the default setting (must not be freed).
+ */
+const gchar *
+mc_profile_get_default_setting (McProfile *id, const gchar *setting)
+{
+ McProtocol *proto;
+ GSList *params, *tmp;
+ McProtocolParam *param;
+ const gchar *def;
+ gboolean profile_loaded;
+
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (setting != NULL, NULL);
+ g_return_val_if_fail (*setting != '\0', NULL);
+
+ profile_loaded = _mc_profile_load (id);
+ g_return_val_if_fail (profile_loaded, NULL);
+
+ def = (const gchar *) g_hash_table_lookup (MC_PROFILE_PRIV (id)->default_settings, setting);
+
+ if (def)
+ {
+ return def;
+ }
+
+ proto = mc_profile_get_protocol (id);
+ params = mc_protocol_get_params (proto);
+
+ for (tmp = params; tmp != NULL; tmp = tmp->next)
+ {
+ param = (McProtocolParam *) tmp->data;
+
+ if ((NULL != param) && (NULL != param->name)
+ && (0 == strcmp(param->name, setting)))
+ {
+ def = param->def;
+ }
+ }
+
+ mc_protocol_free_params_list (params);
+ return def;
+}
diff --git a/libmissioncontrol/mc-profile.h b/libmissioncontrol/mc-profile.h
new file mode 100644
index 00000000..becdef65
--- /dev/null
+++ b/libmissioncontrol/mc-profile.h
@@ -0,0 +1,119 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_PROFILE_H__
+#define __MC_PROFILE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmissioncontrol/mc-protocol.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ MC_PROFILE_CAPABILITY_NONE = 0,
+ MC_PROFILE_CAPABILITY_CHAT_P2P = 1 << 0,
+ MC_PROFILE_CAPABILITY_CHAT_ROOM = 1 << 1,
+ MC_PROFILE_CAPABILITY_CHAT_ROOM_LIST = 1 << 2,
+ MC_PROFILE_CAPABILITY_VOICE_P2P = 1 << 3,
+ MC_PROFILE_CAPABILITY_CONTACT_SEARCH = 1 << 4,
+ MC_PROFILE_CAPABILITY_SPLIT_ACCOUNT = 1 << 5,
+ MC_PROFILE_CAPABILITY_REGISTRATION_UI = 1 << 6,
+ MC_PROFILE_CAPABILITY_SUPPORTS_AVATARS = 1 << 7,
+} McProfileCapabilityFlags;
+
+typedef struct {
+ GObject parent;
+ gpointer priv;
+} McProfile;
+
+#define MC_TYPE_PROFILE mc_profile_get_type()
+
+#define MC_PROFILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MC_TYPE_PROFILE, McProfile))
+
+#define MC_PROFILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MC_TYPE_PROFILE, McProfilewClass))
+
+#define MC_IS_PROFILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MC_TYPE_PROFILE))
+
+#define MC_IS_PROFILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MC_TYPE_PROFILE))
+
+#define MC_PROFILE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MC_TYPE_PROFILE, McProfilewClass))
+
+typedef struct {
+ GObjectClass parent_class;
+} McProfileClass;
+
+#include <libmissioncontrol/mission-control.h>
+
+GType mc_profile_get_type (void);
+
+McProfile* mc_profile_new (const gchar *unique_name);
+
+/* to find one profile */
+McProfile *mc_profile_lookup (const gchar *unique_name);
+McProfile *mc_profile_lookup_default_for_vcard_field (const gchar *vcard_field);
+void mc_profile_free (McProfile *id);
+void mc_profile_clear_cache (void);
+
+/* to find many profiles */
+GList *mc_profiles_list (void);
+GList *mc_profiles_list_by_vcard_field (const gchar *vcard_field);
+void mc_profiles_free_list (GList *list);
+
+const gchar *mc_profile_get_unique_name (McProfile *id);
+const gchar *mc_profile_get_configuration_ui (McProfile *id);
+const gchar *mc_profile_get_display_name (McProfile *id);
+const gchar *mc_profile_get_icon_name (McProfile *id);
+const gchar *mc_profile_get_branding_icon_name (McProfile *id);
+const gchar *mc_profile_get_vcard_field (McProfile *id);
+const gchar *mc_profile_get_default_account_domain (McProfile *id);
+const McPresence *mc_profile_get_supported_presences (McProfile *id);
+gboolean mc_profile_supports_presence (McProfile *id, McPresence presence);
+McProtocol *mc_profile_get_protocol (McProfile *id);
+
+/* only use this protocol name instead of the real McProfile if you do
+ * not care about being able to discover the correct connection manager
+ * and hence which options are valid when connecting a certain account.
+ * without the manager name also, the protocol name is not sufficient
+ * to look up an McProfile. this is intentional. */
+const gchar *mc_profile_get_protocol_name (McProfile *id);
+
+gboolean mc_profile_is_default_for_vcard_field (McProfile *id);
+McProfileCapabilityFlags mc_profile_get_capabilities (McProfile *id);
+const gchar *mc_profile_get_default_setting (McProfile *id, const gchar *setting);
+
+G_END_DECLS
+
+#endif /* __MC_PROFILE_H__ */
diff --git a/libmissioncontrol/mc-protocol-priv.h b/libmissioncontrol/mc-protocol-priv.h
new file mode 100644
index 00000000..9be7739d
--- /dev/null
+++ b/libmissioncontrol/mc-protocol-priv.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_PROTOCOL_PRIV_H__
+#define __MC_PROTOCOL_PRIV_H__
+
+McProtocol * _mc_protocol_from_keyfile (
+ GKeyFile *keyfile, const gchar *manager_name, const gchar *group_name,
+ const gchar *unique_name);
+
+#endif /* __MC_PROTOCOL_PRIV_H__ */
+
diff --git a/libmissioncontrol/mc-protocol.c b/libmissioncontrol/mc-protocol.c
new file mode 100644
index 00000000..e6e79f71
--- /dev/null
+++ b/libmissioncontrol/mc-protocol.c
@@ -0,0 +1,367 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define DBUS_API_SUBJECT_TO_CHANGE 1
+
+#include <dbus/dbus.h>
+#include <glib.h>
+#include <string.h>
+
+#include "mc-manager.h"
+#include "mc-manager-priv.h"
+
+#include "mc-protocol.h"
+#include "mc-protocol-priv.h"
+
+#define MC_PROTOCOL_PRIV(protocol) ((McProtocolPrivate *)protocol->priv)
+
+G_DEFINE_TYPE (McProtocol, mc_protocol, G_TYPE_OBJECT);
+
+typedef struct
+{
+ gchar *manager;
+ gchar *name;
+ GSList *params;
+} McProtocolPrivate;
+
+static void
+mc_protocol_init (McProtocol *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ MC_TYPE_PROTOCOL, McProtocolPrivate);
+}
+
+static McProtocol *
+_mc_protocol_new (const gchar *manager, const gchar *name, GSList *params)
+{
+ McProtocol *new = g_object_new (MC_TYPE_PROTOCOL, NULL);
+ McProtocolPrivate *priv = MC_PROTOCOL_PRIV (new);
+
+ priv->manager = g_strdup (manager);
+ priv->name = g_strdup (name);
+ priv->params = params;
+ return new;
+}
+
+static void
+mc_protocol_finalize (GObject *object)
+{
+ McProtocol *protocol = MC_PROTOCOL (object);
+ McProtocolPrivate *priv = MC_PROTOCOL_PRIV (protocol);
+ McProtocolParam *param;
+ GSList *i;
+
+ g_free (priv->manager);
+ g_free (priv->name);
+
+ for (i = priv->params; NULL != i; i = i->next)
+ {
+ param = (McProtocolParam *) i->data;
+
+ g_free (i->data);
+ }
+
+ g_slist_free (priv->params);
+}
+
+static void
+mc_protocol_class_init (McProtocolClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McProtocolPrivate));
+ object_class->finalize = mc_protocol_finalize;
+}
+
+/**
+ * mc_protocol_lookup:
+ * @id: The #McManager.
+ * @protocol: The protocol name.
+ *
+ * Looks up the protocol having the given name in the manager's supported
+ * protocols. The returned object's reference count is incremented.
+ *
+ * Returns: the #McProtocol, or NULL if not found.
+ */
+McProtocol *
+mc_protocol_lookup (McManager *manager, const gchar *protocol)
+{
+ return _mc_manager_protocol_lookup (manager, protocol);
+}
+
+/**
+ * mc_protocol_free:
+ * @id: The #McProtocol.
+ *
+ * Frees (unrefs) the protocol.
+ */
+void
+mc_protocol_free (McProtocol *id)
+{
+ g_return_if_fail (id != NULL);
+
+ g_object_unref (id);
+}
+
+/**
+ * mc_protocols_list:
+ *
+ * Lists all supported protocols. <emphasis>This currently lists all protocols
+ * supported by the "gabble" manager</emphasis>.
+ *
+ * Returns: a #GList of #McProtocol, to be freed with #mc_protocols_free_list.
+ */
+GList *
+mc_protocols_list (void)
+{
+ return mc_protocols_list_by_manager (mc_manager_lookup ("gabble"));
+}
+
+/**
+ * mc_protocols_list_by_manager:
+ * @id: a #McManager.
+ *
+ * Lists all protocols supported by the given manager.
+ *
+ * Returns: a #GList of #McProtocol, to be freed with #mc_protocols_free_list.
+ */
+GList *
+mc_protocols_list_by_manager (McManager *id)
+{
+ return g_list_prepend (NULL, mc_protocol_lookup (id, "jabber"));
+}
+
+/**
+ * mc_protocols_free_list:
+ * @list: a #GList of #McProtocol.
+ *
+ * Frees a list of protocols.
+ */
+void
+mc_protocols_free_list (GList *list)
+{
+ GList *tmp;
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next)
+ mc_protocol_free ((McProtocol *) tmp->data);
+
+ g_list_free (list);
+}
+
+/**
+ * mc_protocol_get_manager:
+ * @id: The #McProtocol.
+ *
+ * Gets the manager for this protocol.
+ *
+ * Returns: the #McManager, or NULL if some error occurred.
+ */
+McManager *
+mc_protocol_get_manager (McProtocol *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return mc_manager_lookup (MC_PROTOCOL_PRIV (id)->manager);
+}
+
+/**
+ * mc_protocol_get_name:
+ * @id: The #McProtocol.
+ *
+ * Gets the name of this protocol.
+ *
+ * Returns: a string representing the name (not to be freed)
+ */
+const gchar *
+mc_protocol_get_name (McProtocol *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return MC_PROTOCOL_PRIV (id)->name;
+}
+
+/**
+ * mc_protocol_get_params:
+ * @protocol: The #McProtocol.
+ *
+ * Gets the parameters for this protocol.
+ *
+ * Returns: a #GList of #McProtocolParam, to be freed with
+ * #mc_protocol_free_params_list.
+ */
+GSList *
+mc_protocol_get_params (McProtocol *protocol)
+{
+ McProtocolPrivate *priv = MC_PROTOCOL_PRIV (protocol);
+
+ return g_slist_copy (priv->params);
+}
+
+/**
+ * mc_protocol_free_params_list:
+ * @list: The #GList.
+ *
+ * Frees a list of #McProtocolParam.
+ */
+void
+mc_protocol_free_params_list (GSList *list)
+{
+ g_slist_free (list);
+}
+
+static McProtocolParam *
+_parse_parameter (const gchar *name, const gchar *s)
+{
+ McProtocolParam *new;
+ gchar **bits;
+ gchar **i;
+
+ bits = g_strsplit (s, " ", 0);
+
+ if (NULL == *bits)
+ {
+ g_debug ("%s: param \"%s\" has no signature", G_STRFUNC, name);
+ return NULL;
+ }
+
+ if (1 != strlen (*bits))
+ {
+ g_debug ("%s: param \"%s\" has invalid signature", G_STRFUNC, name);
+ return NULL;
+ }
+
+ new = g_new0 (McProtocolParam, 1);
+ new->name = g_strdup (name);
+ new->signature = g_strdup (*bits);
+ new->def = NULL;
+
+ for (i = bits + 1; NULL != *i; i++)
+ {
+ if (0 == strcmp (*i, "required"))
+ new->flags |= MC_PROTOCOL_PARAM_REQUIRED;
+ else if (0 == strcmp (*i, "register"))
+ new->flags |= MC_PROTOCOL_PARAM_REGISTER;
+ else
+ g_debug ("%s: unrecognised parameter flag \"%s\"", G_STRFUNC, *i);
+ }
+
+ g_strfreev (bits);
+ return new;
+}
+
+#define PREFIX_PARAM "param-"
+#define PREFIX_PARAM_LEN 6
+#define PREFIX_DEFAULT "default-"
+#define PREFIX_DEFAULT_LEN 8
+
+static gint
+find_param_by_name_func(gconstpointer a, gconstpointer b)
+{
+ McProtocolParam *param = (McProtocolParam *) a;
+ const gchar *name = (const gchar *) b;
+
+ return !((NULL != param->name) && (NULL != name)
+ && (0 == strcmp(param->name, name)));
+}
+
+McProtocol *
+_mc_protocol_from_keyfile (GKeyFile *keyfile, const gchar *manager_name,
+ const gchar *group_name, const gchar *name)
+{
+ GSList *params = NULL;
+ gchar **keys;
+ gchar **i;
+
+ g_assert (name);
+ keys = g_key_file_get_keys (keyfile, group_name, NULL, NULL);
+
+ if (!keys)
+ {
+ g_debug ("%s: failed to get keys from file", G_STRFUNC);
+ return NULL;
+ }
+
+ for (i = keys; NULL != *i; i++)
+ {
+ McProtocolParam *param;
+ const gchar *name = *i;
+ gchar *value = g_key_file_get_string (keyfile, group_name, *i, NULL);
+
+ if (0 == strncmp (*i, PREFIX_PARAM, PREFIX_PARAM_LEN))
+ {
+ name += PREFIX_PARAM_LEN;
+ param = _parse_parameter (name, value);
+
+ if (param)
+ params = g_slist_prepend (params, param);
+ }
+ else if (0 == strncmp (*i, PREFIX_DEFAULT, PREFIX_DEFAULT_LEN))
+ {
+ GSList *node;
+
+ name += PREFIX_DEFAULT_LEN;
+ node = g_slist_find_custom (params, name, find_param_by_name_func);
+
+ if (node)
+ {
+ param = (McProtocolParam *) node->data;
+
+ if (!param->def)
+ param->def = g_strdup(value);
+ else
+ g_warning("%s: encountered multiple default values for parameter \"%s\"", G_STRFUNC, name);
+ }
+ }
+ else
+ {
+ g_debug ("%s: unrecognised protocol key \"%s\"", G_STRFUNC, *i);
+ }
+
+ g_free (value);
+ }
+
+ g_strfreev (keys);
+
+ return _mc_protocol_new (manager_name, name, params);
+}
+
+/**
+ * mc_protocol_print:
+ * @protocol: the #McProtocol.
+ *
+ * Prints the protocol name and all protocol parameters via #g_print.
+ */
+void
+mc_protocol_print (McProtocol *protocol)
+{
+ GSList *i;
+
+ g_print ("protocol: %s\n", mc_protocol_get_name (protocol));
+
+ for (i = mc_protocol_get_params (protocol); NULL != i; i = i->next)
+ {
+ McProtocolParam *param = (McProtocolParam *) i->data;
+
+ g_print (" %s:%s:%s\n", param->signature, param->name, param->def);
+ }
+}
+
diff --git a/libmissioncontrol/mc-protocol.h b/libmissioncontrol/mc-protocol.h
new file mode 100644
index 00000000..339f91d3
--- /dev/null
+++ b/libmissioncontrol/mc-protocol.h
@@ -0,0 +1,103 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MC_PROTOCOL_H__
+#define __MC_PROTOCOL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmissioncontrol/mc-manager.h>
+
+G_BEGIN_DECLS
+
+#define MC_TYPE_PROTOCOL mc_protocol_get_type()
+
+#define MC_PROTOCOL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MC_TYPE_PROTOCOL, McProtocol))
+
+#define MC_PROTOCOL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MC_TYPE_PROTOCOL, McProtocolClass))
+
+#define MC_IS_PROTOCOL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MC_TYPE_PROTOCOL))
+
+#define MC_IS_PROTOCOL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MC_TYPE_PROTOCOL))
+
+#define MC_PROTOCOL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MC_TYPE_PROTOCOL, McProtocolClass))
+
+GType mc_protocol_get_type (void);
+
+typedef struct {
+ GObject parent;
+ gpointer priv;
+} McProtocol;
+
+typedef struct {
+ GObjectClass parent_class;
+} McProtocolClass;
+
+/* protocols are only unique within the context of a particular manager */
+McProtocol *mc_protocol_lookup (McManager *id, const gchar *protocol);
+void mc_protocol_free (McProtocol *id);
+
+GList *mc_protocols_list (void);
+GList *mc_protocols_list_by_manager (McManager *id);
+void mc_protocols_free_list (GList *list);
+
+McManager *mc_protocol_get_manager (McProtocol *id);
+const gchar *mc_protocol_get_name (McProtocol *id);
+
+enum
+{
+ MC_PROTOCOL_PARAM_REQUIRED = 1 << 0,
+ MC_PROTOCOL_PARAM_REGISTER = 1 << 1
+};
+
+/* return type for params */
+typedef struct
+{
+ const gchar *name;
+ const gchar *signature;
+ const gchar *def;
+ guint flags;
+} McProtocolParam;
+
+/* Returns list of McProtocolParam. */
+GSList *mc_protocol_get_params (McProtocol *protocol);
+
+/* Frees the lists above and all data */
+void mc_protocol_free_params_list (GSList *list);
+
+void mc_protocol_print (McProtocol *protocol);
+
+G_END_DECLS
+
+#endif /* __MC_PROTOCOL_H__ */
diff --git a/libmissioncontrol/mc.c b/libmissioncontrol/mc.c
new file mode 100644
index 00000000..f78a44e8
--- /dev/null
+++ b/libmissioncontrol/mc.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <gmodule.h>
+
+#include "mc.h"
+
+#define LIBRARY_FILE G_STRINGIFY(LIBDIR) "/libmissioncontrol-config.so." G_STRINGIFY(LIBVERSION)
+
+/**
+ * mc_make_resident:
+ *
+ * This function is a workaround for problems with mc getting loaded twice
+ * into the same process, such as when the control panel loads a plugin which
+ * uses mc after it has already been loaded and unloaded. In order to
+ * prevent g_type_register_static being called twice, this function can be
+ * called to make mc be redident in memory for the lifetime of the process.
+ */
+
+void
+mc_make_resident (void)
+{
+ GModule *module = g_module_open (LIBRARY_FILE, 0);
+ if (NULL == module)
+ {
+ g_critical("%s: g_module_open() failed: %s", G_STRFUNC, g_module_error());
+ }
+ g_module_make_resident (module);
+}
+
diff --git a/libmissioncontrol/mc.h b/libmissioncontrol/mc.h
new file mode 100644
index 00000000..0dc16017
--- /dev/null
+++ b/libmissioncontrol/mc.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+G_BEGIN_DECLS
+
+void mc_make_resident (void);
+
+G_END_DECLS
+
diff --git a/libmissioncontrol/mission-control-signals-marshal.list b/libmissioncontrol/mission-control-signals-marshal.list
new file mode 100644
index 00000000..07acaf90
--- /dev/null
+++ b/libmissioncontrol/mission-control-signals-marshal.list
@@ -0,0 +1,5 @@
+VOID:UINT,UINT,UINT,STRING
+VOID:STRING,UINT
+VOID:UINT,UINT
+VOID:UINT,STRING,UINT
+VOID:UINT
diff --git a/libmissioncontrol/mission-control.c b/libmissioncontrol/mission-control.c
new file mode 100644
index 00000000..5639f84e
--- /dev/null
+++ b/libmissioncontrol/mission-control.c
@@ -0,0 +1,1110 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "mc-client-lib-gen.h"
+#include "mission-control.h"
+#include "mission-control-signals-marshal.h"
+#include <glib.h>
+#include <string.h>
+
+static void _handle_mcd_errors (DBusGProxy * missioncontrol, guint serial,
+ gchar *client_id, guint reason,
+ gpointer userdata);
+
+static gboolean check_for_accounts (MissionControl * self);
+
+static GObjectClass *parent_class = NULL;
+static guint operation_id; /* A simple counter for execution order tracking;
+ must be global per process */
+static GList *instances = NULL;
+static DBusConnection *dbus_connection = NULL;
+static gboolean mc_is_running = FALSE;
+
+/* Signals */
+
+enum
+{
+ ERROR,
+ SERVICE_ENDED,
+ LAST_SIGNAL
+};
+
+static guint libmc_signals[LAST_SIGNAL] = { 0 };
+
+struct dbus_cb_data {
+ McCallback callback;
+ gpointer user_data;
+};
+
+struct get_current_status_cb_data {
+ McGetCurrentStatusCallback callback;
+ gpointer user_data;
+};
+
+#define INVOKE_CALLBACK(mc, callback, data, code, ...) \
+ if (callback) { \
+ GError *error = NULL; \
+ error = g_error_new (MC_ERROR, code, __VA_ARGS__); \
+ callback (mc, error, data); \
+ }
+
+static void
+dbus_async_cb (DBusGProxy * proxy, GError * error, gpointer userdata)
+{
+ struct dbus_cb_data *cb_data = (struct dbus_cb_data *)userdata;
+
+ if (error)
+ g_debug ("%s: Error: %s (%u)", G_STRFUNC, error->message, error->code);
+
+ if (cb_data->callback)
+ cb_data->callback ((MissionControl *)proxy, error, cb_data->user_data);
+ else
+ {
+ /* there's callback to free the error; we must do that ourselves */
+ if (error)
+ g_error_free (error);
+ }
+
+ g_free (cb_data);
+}
+
+static DBusHandlerResult
+dbus_filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ gpointer data)
+{
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_signal (message,
+ "org.freedesktop.DBus",
+ "NameOwnerChanged")) {
+ const gchar *name = NULL;
+ const gchar *prev_owner = NULL;
+ const gchar *new_owner = NULL;
+ DBusError error = {0};
+
+ dbus_error_init (&error);
+
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING,
+ &name,
+ DBUS_TYPE_STRING,
+ &prev_owner,
+ DBUS_TYPE_STRING,
+ &new_owner,
+ DBUS_TYPE_INVALID)) {
+
+ g_debug ("error: %s", error.message);
+ dbus_error_free (&error);
+
+ return result;
+ }
+
+ if (name &&
+ strcmp (name, MISSION_CONTROL_SERVICE) == 0)
+ {
+ if (prev_owner && prev_owner[0] != '\0')
+ {
+ GList *list;
+
+ for (list = instances; list; list = list->next)
+ g_signal_emit (list->data, libmc_signals[SERVICE_ENDED], 0);
+ }
+ mc_is_running = new_owner && (new_owner[0] != '\0');
+ }
+ }
+
+ return result;
+}
+
+GQuark mission_control_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (quark == 0)
+ quark = g_quark_from_static_string ("mission-control-quark");
+ return quark;
+}
+
+static void instance_finalized (gpointer data, GObject *object)
+{
+ instances = g_list_remove (instances, object);
+ if (!instances)
+ {
+ dbus_connection_remove_filter (dbus_connection, dbus_filter_func,
+ NULL);
+ dbus_connection_unref (dbus_connection);
+ dbus_connection = NULL;
+ }
+}
+
+static void initialize_dbus_filter (DBusGConnection *connection)
+{
+ DBusError error;
+
+ /* Add a filter to detect the service exits and emit the ServiceEnded
+ * signal accordingly */
+ dbus_connection = dbus_g_connection_get_connection (connection);
+ dbus_connection_ref (dbus_connection);
+ dbus_error_init (&error);
+ dbus_connection_add_filter (dbus_connection,
+ dbus_filter_func,
+ NULL, NULL);
+ dbus_bus_add_match (dbus_connection,
+ "type='signal'," "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged'", &error);
+ if (dbus_error_is_set (&error))
+ {
+ g_warning ("Match rule adding failed");
+ dbus_error_free (&error);
+ }
+
+ mc_is_running = dbus_bus_name_has_owner (dbus_connection,
+ MISSION_CONTROL_SERVICE, NULL);
+}
+
+static void
+_missioncontrol_register_signal_marshallers (void)
+{
+ /* Register the AccountStatusChanged signal */
+ dbus_g_object_register_marshaller
+ (mission_control_signals_marshal_VOID__UINT_UINT_UINT_STRING,
+ G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
+ G_TYPE_INVALID);
+ /* Register the error signal */
+ dbus_g_object_register_marshaller
+ (mission_control_signals_marshal_VOID__UINT_STRING_UINT, G_TYPE_NONE,
+ G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID);
+ /* Register the PresenceStatusRequested/Actual signal */
+ dbus_g_object_register_marshaller
+ (mission_control_signals_marshal_VOID__UINT, G_TYPE_NONE, G_TYPE_UINT,
+ G_TYPE_INVALID);
+ /* Register the StatusActual signal */
+ dbus_g_object_register_marshaller
+ (mission_control_signals_marshal_VOID__UINT_UINT, G_TYPE_NONE,
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
+ /* Register the UsedChannelsCountChanged signal */
+ dbus_g_object_register_marshaller
+ (mission_control_signals_marshal_VOID__STRING_UINT, G_TYPE_NONE,
+ G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID);
+}
+
+static void
+mission_control_init (GTypeInstance * instance, gpointer g_class)
+{
+ MissionControl *self = MISSIONCONTROL (instance);
+ self->first_run = TRUE;
+}
+
+
+static void
+mission_control_dispose (GObject * obj)
+{
+ MissionControl *self = MISSIONCONTROL (obj);
+
+ if (self->first_run)
+ {
+ self->first_run = FALSE;
+ }
+
+ if (G_OBJECT_CLASS (parent_class)->dispose)
+ {
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+ }
+}
+
+
+static void
+mission_control_class_init (MissionControlClass * klass)
+{
+ GObjectClass *obj = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ obj->set_property = parent_class->set_property;
+ obj->get_property = parent_class->get_property;
+ obj->dispose = mission_control_dispose;
+ _missioncontrol_register_signal_marshallers ();
+
+ /**
+ * MissionControl::Error:
+ * @self: The #MissionControl object.
+ * @operation_id: The unique ID of the operation which caused the error.
+ * When this signal is emitted to report a failure in handling a channel,
+ * this parameter holds the same @operation_id returned by the channel
+ * request function call.
+ * @error_code: The #MCError code describing the error.
+ *
+ * This signal is emitted when an error is raised from the mission-control
+ * server. This is not raised in response to some API call failing (they
+ * already provide a way to report errors), but rather for informing the
+ * client of some unexpected event, such as a channel handler failing.
+ */
+ libmc_signals[ERROR] =
+ g_signal_new ("Error",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ mission_control_signals_marshal_VOID__UINT_UINT,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
+ /**
+ * MissionControl::ServiceEnded:
+ * @self: The #MissionControl object
+ *
+ * This signal is emitted when a mission-control server process has exited.
+ */
+ libmc_signals[SERVICE_ENDED] =
+ g_signal_new ("ServiceEnded",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+
+GType
+mission_control_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (MissionControlClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) mission_control_class_init,
+ NULL,
+ NULL,
+ sizeof (MissionControl),
+ 0,
+ (GInstanceInitFunc) mission_control_init
+ };
+ type = g_type_register_static (DBUS_TYPE_G_PROXY,
+ "MissionControl", &info, 0);
+ }
+ return type;
+}
+
+
+/**
+ * mission_control_new:
+ * @connection: The D-BUS connection for this object
+ *
+ * Creates a new Mission Control client library object.
+ *
+ * Return value: A new mc (Mission Control) library object, or NULL if unsuccesful
+ */
+MissionControl *
+mission_control_new (DBusGConnection * connection)
+{
+ g_return_val_if_fail (connection != NULL, NULL);
+ MissionControl *mc_obj = NULL;
+
+ /* Create the proxy object that is used for performing
+ * the method calls on the Mission Control service */
+
+ mc_obj = g_object_new (MISSIONCONTROL_TYPE,
+ "name", MISSION_CONTROL_SERVICE,
+ "path", MISSION_CONTROL_PATH,
+ "interface", MISSION_CONTROL_IFACE,
+ "connection", connection, NULL);
+ if (!instances)
+ {
+ /* this is the first instance created in this process:
+ * perform some global initializations */
+ initialize_dbus_filter (connection);
+ }
+ /* Add the object to the list of living MC instances, and add a watch for
+ * its finalization */
+ instances = g_list_prepend (instances, mc_obj);
+ g_object_weak_ref (G_OBJECT (mc_obj), instance_finalized, NULL);
+
+ dbus_g_proxy_add_signal (DBUS_G_PROXY (mc_obj), "AccountStatusChanged",
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
+ G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (DBUS_G_PROXY (mc_obj), "McdError", G_TYPE_UINT,
+ G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (mc_obj), "McdError",
+ G_CALLBACK (_handle_mcd_errors), mc_obj, NULL);
+ dbus_g_proxy_add_signal (DBUS_G_PROXY (mc_obj), "PresenceStatusRequested",
+ G_TYPE_UINT, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (DBUS_G_PROXY (mc_obj), "PresenceStatusActual",
+ G_TYPE_UINT, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (DBUS_G_PROXY (mc_obj), "UsedChannelsCountChanged",
+ G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (DBUS_G_PROXY (mc_obj), "StatusActual",
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
+ return mc_obj;
+}
+
+
+/**
+ * mission_control_set_presence:
+ * @self: The #MissionControl object.
+ * @presence: Integer specifying the presence status code
+ * @message: Optional presence associated message
+ * @callback: a #McCallback function to be notified about any errors
+ * @user_data: data to be passed to the @callback function
+ *
+ * Sets presence for the accounts.
+ */
+void
+mission_control_set_presence (MissionControl * self,
+ McPresence presence, const gchar * message,
+ McCallback callback, gpointer user_data)
+{
+ struct dbus_cb_data *cb_data;
+
+ /* Check whether we have any accounts to set presence for */
+ if (!check_for_accounts (self))
+ {
+ INVOKE_CALLBACK (self, callback, user_data, MC_NO_ACCOUNTS_ERROR, " ");
+ return;
+ }
+
+ cb_data = g_malloc (sizeof (struct dbus_cb_data));
+ g_assert (cb_data != NULL);
+ cb_data->callback = callback;
+ cb_data->user_data = user_data;
+ mission_control_dbus_set_presence_async (DBUS_G_PROXY (self),
+ (gint) presence, message,
+ dbus_async_cb, cb_data);
+}
+
+/**
+ * mission_control_get_presence:
+ * @self: The #MissionControl object.
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Gets the currently requested presence status.
+ *
+ * Return value: The currently requested presence status
+ */
+McPresence
+mission_control_get_presence (MissionControl * self, GError **error)
+{
+ /* To indicate failure, we set the presence to unset */
+ McPresence presence = MC_PRESENCE_UNSET;
+
+ /* Check whether Mission Control is running; if not, it's safe to
+ * say that we're offline without starting it to perform the
+ * query. */
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return MC_PRESENCE_OFFLINE;
+ }
+
+ if (!mission_control_dbus_get_presence (DBUS_G_PROXY (self),
+ &presence, error))
+ {
+ presence = MC_PRESENCE_UNSET;
+ }
+
+ return presence;
+}
+
+/**
+ * mission_control_get_presence_actual:
+ * @self: The #MissionControl object.
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Gets the actual presence status.
+ *
+ * Return value: The actual presence status
+ */
+McPresence
+mission_control_get_presence_actual (MissionControl * self, GError **error)
+{
+ /* To indicate failure, we set the presence to unset */
+ McPresence presence = MC_PRESENCE_UNSET;
+
+ /* Check whether Mission Control is running; if not, it's safe to
+ * say that we're offline without starting it to perform the
+ * query. */
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return MC_PRESENCE_OFFLINE;
+ }
+
+ if (!mission_control_dbus_get_presence_actual (DBUS_G_PROXY (self),
+ &presence, error))
+ {
+ presence = MC_PRESENCE_UNSET;
+ }
+
+ return presence;
+}
+
+/**
+ * mission_control_request_channel:
+ * @self: The #MissionControl object.
+ * @account: The account which will join a new channel or request
+ * joining to an existing channel
+ * @type: a D-Bus interface name representing base channel type
+ * @handle: The handle we want to initiate the communication with
+ * @handle_type: The type of the handle we are initiating the
+ * communication with. See #TelepathyHandleType
+ * @callback: a #McCallback function to be notified about any errors
+ * @user_data: data to be passed to the @callback function
+ *
+ * Requests creation of a new channel, or join to an existing channel.
+ *
+ * Return value: An operation ID which can be used to cancel the request using
+ * #mission_control_cancel_channel_request.
+ */
+guint
+mission_control_request_channel (MissionControl * self,
+ McAccount * account,
+ const gchar * type,
+ guint handle,
+ TelepathyHandleType handle_type,
+ McCallback callback,
+ gpointer user_data)
+{
+ struct dbus_cb_data *cb_data;
+ const gchar *account_name = mc_account_get_unique_name (account);
+ operation_id++;
+
+ if (account_name == NULL)
+ {
+ INVOKE_CALLBACK (self, callback, user_data, MC_INVALID_ACCOUNT_ERROR,
+ " ");
+ return operation_id;
+ }
+
+ /* Check whether we have any accounts to request channel for */
+ if (!check_for_accounts (self))
+ {
+ INVOKE_CALLBACK (self, callback, user_data, MC_NO_ACCOUNTS_ERROR, " ");
+ return operation_id;
+ }
+
+ cb_data = g_malloc (sizeof (struct dbus_cb_data));
+ g_assert (cb_data != NULL);
+ cb_data->callback = callback;
+ cb_data->user_data = user_data;
+ mission_control_dbus_request_channel_async (DBUS_G_PROXY (self),
+ account_name,
+ type, handle, handle_type,
+ operation_id,
+ dbus_async_cb,
+ cb_data);
+
+ return operation_id;
+}
+
+
+/**
+ * mission_control_request_channel_with_string_handle:
+ * @self: The #MissionControl object.
+ * @account: The account which will join a new channel or request joining to an
+ * existing channel
+ * @type: a D-Bus interface name representing base channel type
+ * @handle: The handle we want to initiate the communication with
+ * @handle_type: The type of the handle we are initiating the communication
+ * with. See #TelepathyHandleType
+ * @callback: a #McCallback function to be notified about any errors
+ * @user_data: data to be passed to the @callback function
+ *
+ * Requests creation of a new channel, or join to an existing channel. Differs
+ * from the plain #mission_control_request_channel by taking handles as
+ * strings, which will be resolved to integers by MC.
+ *
+ * Return value: An operation ID which can be used to cancel the request using
+ * #mission_control_cancel_channel_request.
+ */
+guint
+mission_control_request_channel_with_string_handle (MissionControl * self,
+ McAccount * account,
+ const gchar * type,
+ const gchar * handle,
+ TelepathyHandleType
+ handle_type,
+ McCallback callback,
+ gpointer user_data)
+{
+ struct dbus_cb_data *cb_data;
+ operation_id++;
+ const gchar *account_name = mc_account_get_unique_name (account);
+
+ if (account_name == NULL)
+ {
+ INVOKE_CALLBACK (self, callback, user_data, MC_INVALID_ACCOUNT_ERROR,
+ " ");
+ return operation_id;
+ }
+
+ /* Check whether we have any accounts to request channel for */
+ if (!check_for_accounts (self))
+ {
+ INVOKE_CALLBACK (self, callback, user_data, MC_NO_ACCOUNTS_ERROR, " ");
+ return operation_id;
+ }
+
+ cb_data = g_malloc (sizeof (struct dbus_cb_data));
+ g_assert (cb_data != NULL);
+ cb_data->callback = callback;
+ cb_data->user_data = user_data;
+ mission_control_dbus_request_channel_with_string_handle_async
+ (DBUS_G_PROXY (self), account_name, type, handle, handle_type,
+ operation_id,
+ dbus_async_cb, cb_data);
+
+ return operation_id;
+}
+
+/**
+ * mission_control_cancel_channel_request:
+ * @self: The #MissionControl object.
+ * @operation_id: the operation id of the request to cancel, as returned
+ * by #mission_control_request_channel_with_string_handle.
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Cancel a channel request; a process can only cancel the requests that were
+ * originated by itself.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ */
+gboolean
+mission_control_cancel_channel_request (MissionControl *self,
+ guint operation_id,
+ GError **error)
+{
+ return mission_control_dbus_cancel_channel_request (DBUS_G_PROXY (self),
+ operation_id,
+ error);
+}
+
+/**
+ * mission_control_connect_all_with_default_presence:
+ * @self: The #MissionControl object.
+ * @callback: a #McCallback function to be notified about any errors
+ * @user_data: data to be passed to the @callback function
+ *
+ * Connect all accounts using default presence,
+ * or HIDDEN if default presence is OFFLINE.
+ * If accounts are already connected do nothing.
+ */
+void
+mission_control_connect_all_with_default_presence (MissionControl * self,
+ McCallback callback,
+ gpointer user_data)
+{
+ struct dbus_cb_data *cb_data;
+
+ /* Check whether we have any accounts to set presence for */
+ if (!check_for_accounts (self))
+ {
+ INVOKE_CALLBACK (self, callback, user_data, MC_NO_ACCOUNTS_ERROR,
+ " ");
+ return;
+ }
+
+ cb_data = g_malloc (sizeof (struct dbus_cb_data));
+ g_assert (cb_data != NULL);
+ cb_data->callback = callback;
+ cb_data->user_data = user_data;
+ mission_control_dbus_connect_all_with_default_presence_async
+ (DBUS_G_PROXY (self),
+ dbus_async_cb, cb_data);
+}
+
+/**
+ * mission_control_get_connection_status:
+ * @self: The #MissionControl object.
+ * @account: The account whose connection status is inspected
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Request a status code describing the status of the connection that the
+ * provided account currently uses.
+ *
+ * Return value: A status code describing the status of the specified connection
+ * eg. CONNECTED = 0, CONNECTING = 1, DISCONNECTED = 2
+ */
+guint
+mission_control_get_connection_status (MissionControl * self,
+ McAccount * account,
+ GError **error)
+{
+ /* XXX TP_CONN_STATUS_DISCONNECTED is used as an UNKNOWN status is not
+ * available */
+ guint conn_status = TP_CONN_STATUS_DISCONNECTED;
+ const gchar *account_name = mc_account_get_unique_name (account);
+
+ if (account_name == NULL)
+ {
+ g_set_error (error, MC_ERROR, MC_INVALID_ACCOUNT_ERROR, " ");
+ return conn_status;
+ }
+
+ /* Check whether we have any accounts to connection status for */
+ if (!check_for_accounts (self))
+ {
+ g_set_error (error, MC_ERROR, MC_NO_ACCOUNTS_ERROR, " ");
+ return conn_status;
+ }
+
+ /* Check whether Mission Control is running; if not, it's safe to
+ * say that we're offline. */
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return TP_CONN_STATUS_DISCONNECTED;
+ }
+
+ mission_control_dbus_get_connection_status (DBUS_G_PROXY (self),
+ account_name,
+ &conn_status, error);
+ return conn_status;
+}
+
+/**
+ * mission_control_get_online_connections:
+ * @self: The #MissionControl object.
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Request an array of strings representing the account names that have
+ * an active connection.
+ *
+ * Return value: A list of McAccounts corresponding to the online
+ * connections
+ */
+GSList *
+mission_control_get_online_connections (MissionControl * self, GError **error)
+{
+ GSList *online_conns = NULL;
+ gchar **names = NULL;
+
+ /* Check whether we have any accounts, otherwise we do not have
+ * connections either */
+
+ if (!check_for_accounts (self))
+ {
+ g_set_error (error, MC_ERROR, MC_NO_ACCOUNTS_ERROR, " ");
+ return NULL;
+ }
+
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_NO_MATCHING_CONNECTION_ERROR,
+ "MC not running");
+ return NULL;
+ }
+
+ if (!mission_control_dbus_get_online_connections (DBUS_G_PROXY (self),
+ &names, error))
+ {
+ return NULL;
+ }
+ /* Create McAccounts with all the account names */
+ while (*names != NULL)
+ {
+ McAccount *acc = mc_account_lookup (*names);
+
+ if (acc != NULL)
+ {
+ online_conns = g_slist_prepend (online_conns, acc);
+ }
+ *names++;
+ }
+
+ return online_conns;
+}
+
+/**
+ * mission_control_get_connection:
+ * @self: The #MissionControl object.
+ * @account: The account the connection is created for.
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Gets a connection object for the specified account name.
+ *
+ * Return value: An existing TpConn object, NULL if the account is not connected
+ */
+TpConn *
+mission_control_get_connection (MissionControl * self, McAccount * account,
+ GError **error)
+{
+ TpConn *tp_conn = NULL;
+ gchar *bus_name = NULL, *obj_path = NULL;
+ const gchar *account_name = mc_account_get_unique_name (account);
+ DBusGConnection *connection = NULL;
+
+ if (account_name == NULL)
+ {
+ g_set_error (error, MC_ERROR, MC_INVALID_ACCOUNT_ERROR, " ");
+ return NULL;
+ }
+
+ /* Check whether we have any accounts to request connection for */
+ if (!check_for_accounts (self))
+ {
+ g_set_error (error, MC_ERROR, MC_NO_ACCOUNTS_ERROR, " ");
+ return NULL;
+ }
+
+ /* If MC isn't running there won't be any connections. */
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return NULL;
+ }
+
+ g_object_get (G_OBJECT (self), "connection", &connection, NULL);
+
+ if (connection == NULL)
+ {
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR,
+ "Cannot get D-BUS connection");
+ return NULL;
+ }
+
+ /* Match the account name and corresponding connection parameters in
+ * Mission Control */
+
+ if (!mission_control_dbus_get_connection (DBUS_G_PROXY (self), account_name,
+ &bus_name, &obj_path, error))
+ {
+ dbus_g_connection_unref (connection);
+ return NULL;
+ }
+
+ /* Create a local copy of the TpConn object from the acquired information.
+ * We do not need to use the connect method via a connection manager,
+ * because the connection is already initialized by MissionControl. */
+
+ tp_conn = tp_conn_new (connection, bus_name, obj_path);
+
+ if (tp_conn == NULL)
+ {
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR,
+ "Cannot get telepathy connection");
+ }
+
+ g_free (bus_name);
+ g_free (obj_path);
+ dbus_g_connection_unref (connection);
+
+ return tp_conn;
+}
+
+/**
+ * mission_control_get_account_for_connection:
+ * @self: The #MissionControl object.
+ * @connection: connection object to get the account for
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Gets the account corresponding to the connection object.
+ * Note that as a result the caller owns a reference to the account object.
+ *
+ * Return value: The matching account object, NULL on error
+ */
+McAccount *
+mission_control_get_account_for_connection (MissionControl * self,
+ TpConn * connection,
+ GError **error)
+{
+ const gchar *connection_object_path;
+ gchar *account_unique_name;
+ McAccount *account;
+
+ /* Check whether Mission Control is running; if not, it's safe to
+ * say that there are no accounts or connections in that case
+ * without starting it to perform the query. */
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return NULL;
+ }
+
+ connection_object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (connection));
+
+ if (!mission_control_dbus_get_account_for_connection (DBUS_G_PROXY (self),
+ connection_object_path,
+ &account_unique_name,
+ error))
+ {
+ g_warning ("%s: Getting account for the connection failed", G_STRFUNC);
+ return NULL;
+ }
+
+ account = mc_account_lookup (account_unique_name);
+
+ g_free (account_unique_name);
+
+ return account;
+}
+
+/**
+ * mission_control_get_used_channels_count:
+ * @self: The #MissionControl object.
+ * @type: Type of the counted channels as a GQuark (see the defines in
+ * tp-chan.h)
+ * @error: address where an error can be returned, or NULL.
+ *
+ * Counts the number of active channels of specified type.
+ *
+ * Return value: The number of channels currently in use (negative if the query
+ * fails)
+ */
+gint mission_control_get_used_channels_count(MissionControl *self,
+ GQuark type, GError **error)
+{
+ gint ret;
+
+ /* Check whether Mission Control is running; if not, there should be
+ no active channels without starting it to perform the query. */
+
+ if (!mc_is_running)
+ {
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return 0;
+ }
+
+ /* We'll have to convert the quark here to a string, because it will
+ not match the quarks in another process */
+
+ if (!mission_control_dbus_get_used_channels_count(DBUS_G_PROXY(self),
+ g_quark_to_string(type),
+ (gint *)&ret,
+ error))
+ {
+ /* We'll have to make a difference between a failed request and 0
+ channels in use */
+ return -1;
+ }
+
+ return ret;
+}
+
+static void
+get_current_status_cb (DBusGProxy * proxy,
+ McStatus status,
+ McPresence presence,
+ McPresence requested_presence,
+ GPtrArray *accounts_array,
+ GError *error, gpointer userdata)
+{
+ struct get_current_status_cb_data *cb_data = (struct get_current_status_cb_data *)userdata;
+ McAccountStatus *accounts, *account;
+ GType type;
+ gsize n_accounts;
+ gint i;
+
+ if (error)
+ g_debug ("%s: Error: %s (%u)", G_STRFUNC, error->message, error->code);
+
+ type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT,
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
+ accounts = g_new (McAccountStatus, accounts_array->len);
+ for (i = 0, account = accounts; i < accounts_array->len; i++, account++)
+ {
+ GValue account_value = { 0, };
+
+ g_value_init (&account_value, type);
+ g_value_take_boxed (&account_value,
+ g_ptr_array_index (accounts_array, i));
+ dbus_g_type_struct_get (&account_value,
+ 0, &account->unique_name,
+ 1, &account->status,
+ 2, &account->presence,
+ 3, &account->reason,
+ G_MAXUINT);
+ g_value_unset (&account_value);
+ }
+ n_accounts = accounts_array->len;
+
+ g_ptr_array_free (accounts_array, TRUE);
+ cb_data->callback ((MissionControl *)proxy,
+ status, presence, requested_presence,
+ accounts, n_accounts,
+ error, cb_data->user_data);
+
+ g_free (cb_data);
+}
+
+/**
+ * mission_control_get_current_status:
+ * @self: The #MissionControl object.
+ * @callback: a #McGetCurrentStatusCallback function which will be called with
+ * the requested information.
+ * @user_data: data to be passed to the @callback function
+ *
+ * Queries the status of all the enabled accounts, as well as the global
+ * presence and status. This information will be returned in the registered
+ * @callback, which will be resposible for freeing all the dynamic data.
+ */
+void
+mission_control_get_current_status (MissionControl * self,
+ McGetCurrentStatusCallback callback,
+ gpointer user_data)
+{
+ struct get_current_status_cb_data *cb_data;
+
+ /* Check whether Mission Control is running; if not, it's safe to
+ * say that we're offline without starting it to perform the
+ * query. */
+ g_assert (callback != NULL);
+ if (!mc_is_running)
+ {
+ GError *error = NULL;
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ error = g_error_new (MC_ERROR, MC_DISCONNECTED_ERROR, " ");
+ callback (self, 0, 0, 0, NULL, 0, error, user_data);
+ return;
+ }
+
+ cb_data = g_malloc (sizeof (struct get_current_status_cb_data));
+ g_assert (cb_data != NULL);
+ cb_data->callback = callback;
+ cb_data->user_data = user_data;
+ mission_control_dbus_get_current_status_async (DBUS_G_PROXY (self),
+ get_current_status_cb,
+ cb_data);
+}
+
+/**
+ * mission_control_free_account_statuses:
+ * @accounts: The array of #McAccountStatus.
+ *
+ * Frees the @accounts array.
+ */
+void
+mission_control_free_account_statuses (McAccountStatus *accounts)
+{
+ McAccountStatus *account;
+
+ for (account = accounts; account != NULL; account++)
+ g_free (account->unique_name);
+ g_free (accounts);
+}
+
+
+/* We handle errors coming via MCD here. If the pid for the error
+ matches our pid, we will emit the signal, otherwise we just
+ silently ignore it to avoid other instances using libmissioncontrol
+ getting confused */
+
+static void
+_handle_mcd_errors (DBusGProxy * missioncontrol, guint serial,
+ gchar *client_id,
+ guint reason, gpointer userdata)
+{
+ MissionControl *self = (MissionControl *) userdata;
+ DBusGConnection *connection;
+ const gchar *self_client_id = NULL;
+
+ g_object_get (G_OBJECT (missioncontrol), "connection", &connection, NULL);
+
+ if (!connection)
+ return;
+
+ self_client_id = dbus_bus_get_unique_name (
+ dbus_g_connection_get_connection (connection));
+ dbus_g_connection_unref (connection);
+
+ g_debug ("%s: client id is %s (error comes for %s)", G_STRFUNC, self_client_id, client_id);
+ if (client_id == NULL || (self_client_id != NULL &&
+ strcmp(client_id, self_client_id) == 0))
+ {
+ g_signal_emit_by_name (self, "Error", serial, reason);
+ }
+}
+
+
+/* A helper function to determine if there are valid accounts. Mainly
+ useful for avoiding useless launches of Mission Control */
+
+static gboolean
+check_for_accounts (MissionControl * self)
+{
+ GList *enabled_accounts = mc_accounts_list_by_enabled (TRUE);
+
+ /* Do we have any enabled accounts? If not, fail. */
+
+ /* ? Should we add another error definition for situations where we
+ * have accounts, but none of them are enabled? */
+
+ if (!enabled_accounts || g_list_length (enabled_accounts) == 0)
+ {
+ mc_accounts_list_free (enabled_accounts);
+ g_debug ("%s: No enabled accounts", G_STRFUNC);
+ return FALSE;
+ }
+
+ mc_accounts_list_free (enabled_accounts);
+ return TRUE;
+}
+
+/**
+ * mission_control_remote_avatar_changed:
+ * @self: the #MissionControl object.
+ * @connection: connection object which received the avatar update.
+ * @contact_id: the Telepathy self contact handle.
+ * @token: the Telepathy token for the new avatar.
+ * @error: address where an error can be returned, or NULL.
+ *
+ * This function is responsible for taking actions in response to the own
+ * avatar being received from the server. Depending on the situation, this
+ * function can update the local avatar in our #McAccount.
+ *
+ * Returns: %TRUE if success, %FALSE if some error occurred.
+ */
+gboolean
+mission_control_remote_avatar_changed (MissionControl *self,
+ TpConn *connection, guint contact_id,
+ const gchar *token, GError **error)
+{
+ const gchar *connection_object_path;
+
+ /* Check whether Mission Control is running; if not, it's safe to
+ * say that there are no accounts or connections in that case
+ * without starting it to perform the query. */
+ if (!mc_is_running)
+ {
+ g_debug ("%s: MC not running.", G_STRFUNC);
+ g_set_error (error, MC_ERROR, MC_DISCONNECTED_ERROR, "MC not running");
+ return FALSE;
+ }
+
+ connection_object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (connection));
+
+ return mission_control_dbus_remote_avatar_changed (DBUS_G_PROXY (self),
+ connection_object_path,
+ contact_id, token,
+ error);
+}
+
+
diff --git a/libmissioncontrol/mission-control.h b/libmissioncontrol/mission-control.h
new file mode 100644
index 00000000..1ea6f59c
--- /dev/null
+++ b/libmissioncontrol/mission-control.h
@@ -0,0 +1,208 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MISSION_CONTROL_LIB_H
+#define MISSION_CONTROL_LIB_H
+
+#ifndef DBUS_API_SUBJECT_TO_CHANGE
+#define DBUS_API_SUBJECT_TO_CHANGE
+#endif
+
+#include "dbus/dbus-glib.h"
+#include "dbus/dbus-glib-lowlevel.h"
+#include "dbus/dbus.h"
+#include <libtelepathy/tp-constants.h>
+#include <libtelepathy/tp-conn.h>
+#include <libtelepathy/tp-chan.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define MISSION_CONTROL_SERVICE "org.freedesktop.Telepathy.MissionControl"
+#define MISSION_CONTROL_IFACE "org.freedesktop.Telepathy.MissionControl"
+#define MISSION_CONTROL_PATH "/org/freedesktop/Telepathy/MissionControl"
+
+#define MISSIONCONTROL_TYPE (mission_control_get_type ())
+
+#define MISSIONCONTROL(obj) (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), MISSIONCONTROL_TYPE, \
+ MissionControl))
+
+#define MISSIONCONTROL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST \
+ ((klass), MISSIONCONTROL_TYPE, \
+ MissionControlClass))
+
+#define IS_MISSIONCONTROL(obj) (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), MISSIONCONTROL_TYPE))
+
+#define IS_MISSIONCONTROL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE \
+ ((klass), MISSIONCONTROL_TYPE))
+
+#define MISSIONCONTROL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), MISSIONCONTROL_TYPE, \
+ MissionControlClass))
+
+#define MC_ERROR (mission_control_error_quark())
+
+typedef struct _missioncontrol MissionControl;
+typedef struct _missioncontrolclass MissionControlClass;
+
+typedef enum {
+ MC_DISCONNECTED_ERROR,
+ MC_INVALID_HANDLE_ERROR,
+ MC_NO_MATCHING_CONNECTION_ERROR,
+ MC_INVALID_ACCOUNT_ERROR,
+ MC_PRESENCE_FAILURE_ERROR,
+ MC_NO_ACCOUNTS_ERROR,
+ MC_NETWORK_ERROR,
+ MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR,
+ MC_LOWMEM_ERROR,
+ MC_CHANNEL_REQUEST_GENERIC_ERROR,
+ MC_CHANNEL_BANNED_ERROR,
+ MC_CHANNEL_FULL_ERROR,
+ MC_CHANNEL_INVITE_ONLY_ERROR,
+ MC_LAST_ERROR /*< skip >*/
+} MCError;
+
+typedef enum {
+ MC_PRESENCE_UNSET,
+ MC_PRESENCE_OFFLINE,
+ MC_PRESENCE_AVAILABLE,
+ MC_PRESENCE_AWAY,
+ MC_PRESENCE_EXTENDED_AWAY,
+ MC_PRESENCE_HIDDEN,
+ MC_PRESENCE_DO_NOT_DISTURB,
+ LAST_MC_PRESENCE /*< skip >*/
+} McPresence;
+
+typedef enum {
+ MC_STATUS_DISCONNECTED,
+ MC_STATUS_CONNECTING,
+ MC_STATUS_CONNECTED,
+} McStatus;
+
+struct _missioncontrol
+{
+ DBusGProxy parent;
+
+ gboolean first_run;
+};
+
+
+struct _missioncontrolclass
+{
+ DBusGProxyClass parent_class;
+};
+
+typedef struct _McAccountStatus {
+ gchar *unique_name;
+ TelepathyConnectionStatus status;
+ McPresence presence;
+ TelepathyConnectionStatusReason reason;
+} McAccountStatus;
+
+typedef void (*McCallback) (MissionControl *mc,
+ GError *error,
+ gpointer user_data);
+
+#include <libmissioncontrol/mc-account.h>
+
+GQuark mission_control_error_quark (void);
+GType mission_control_get_type (void);
+
+
+MissionControl *mission_control_new (DBusGConnection *connection);
+
+void mission_control_set_presence (MissionControl *self,
+ McPresence presence,
+ const gchar *message,
+ McCallback callback,
+ gpointer user_data);
+
+McPresence mission_control_get_presence (MissionControl *self, GError **error);
+McPresence mission_control_get_presence_actual (MissionControl *self,
+ GError **error);
+
+guint mission_control_request_channel (MissionControl *self,
+ McAccount *account,
+ const gchar *type,
+ guint handle,
+ TelepathyHandleType handle_type,
+ McCallback callback,
+ gpointer user_data);
+
+guint mission_control_request_channel_with_string_handle (MissionControl *self,
+ McAccount *account,
+ const gchar *type,
+ const gchar *handle,
+ TelepathyHandleType handle_type,
+ McCallback callback,
+ gpointer user_data);
+
+gboolean mission_control_cancel_channel_request (MissionControl *self,
+ guint operation_id,
+ GError **error);
+
+void mission_control_connect_all_with_default_presence (MissionControl *self,
+ McCallback callback,
+ gpointer user_data);
+
+guint mission_control_get_connection_status (MissionControl *self,
+ McAccount *account,
+ GError **error);
+
+GSList *mission_control_get_online_connections (MissionControl *self,
+ GError **error);
+
+TpConn *mission_control_get_connection (MissionControl *self,
+ McAccount *account, GError **error);
+
+McAccount *mission_control_get_account_for_connection (MissionControl *self,
+ TpConn *connection,
+ GError **error);
+
+gint mission_control_get_used_channels_count (MissionControl *self,
+ GQuark type, GError **error);
+
+typedef void (*McGetCurrentStatusCallback) (MissionControl *mc,
+ McStatus status,
+ McPresence presence,
+ McPresence requested_presence,
+ McAccountStatus *accounts,
+ gsize n_accounts,
+ GError *error,
+ gpointer user_data);
+
+void mission_control_get_current_status (MissionControl *self,
+ McGetCurrentStatusCallback callback,
+ gpointer user_data);
+
+void mission_control_free_account_statuses (McAccountStatus *accounts);
+
+gboolean mission_control_remote_avatar_changed (MissionControl *self,
+ TpConn *connection,
+ guint contact_id,
+ const gchar *token,
+ GError **error);
+
+#endif
diff --git a/libmissioncontrol/test.c b/libmissioncontrol/test.c
new file mode 100644
index 00000000..fca3c561
--- /dev/null
+++ b/libmissioncontrol/test.c
@@ -0,0 +1,491 @@
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include <glib.h>
+
+#include "mc.h"
+#include "mc-account.h"
+#include "mc-account-monitor.h"
+#include "mc-profile.h"
+
+void print_profile (McProfile *profile)
+{
+ const gchar *name, *protocol_name;
+ McProtocol *protocol;
+
+ g_assert (NULL != profile);
+ name = mc_profile_get_unique_name (profile);
+ protocol = mc_profile_get_protocol (profile);
+ protocol_name = mc_protocol_get_name (protocol);
+ printf ("profile: %s (%s)\n", name, protocol_name);
+}
+
+void print_account (McAccount *account)
+{
+ const gchar *name = mc_account_get_unique_name (account);
+ printf ("account: %p (%s)\n", account, name);
+}
+
+void print_manager (McManager *manager)
+{
+ const gchar *name = mc_manager_get_unique_name (manager);
+ printf ("manager: %p (%s)\n", manager, name);
+}
+
+void print_protocol (McProtocol *protocol)
+{
+ printf ("protocol: %s/%s\n",
+ mc_manager_get_unique_name (
+ mc_protocol_get_manager (protocol)),
+ mc_protocol_get_name (protocol));
+}
+
+void print_protocol_detailed (McProtocol *protocol)
+{
+ GSList *i;
+
+ g_assert (NULL != protocol);
+ print_protocol (protocol);
+
+ for (i = mc_protocol_get_params (protocol); NULL != i; i = i->next)
+ {
+ McProtocolParam *param = (McProtocolParam *) i->data;
+
+ printf(" %s:%s\n", param->signature, param->name);
+ }
+}
+
+void test_profile ()
+{
+ McProfile *profile1, *profile2;
+ McProtocol *protocol;
+ const gchar * protocol_name;
+
+ profile1 = mc_profile_lookup ("testprofile");
+ g_assert (profile1);
+ g_assert (0 == strcmp ("testprofile",
+ mc_profile_get_unique_name (profile1)));
+ protocol_name = mc_profile_get_protocol_name (profile1);
+ g_assert (0 == strcmp ("testproto", protocol_name));
+ protocol = mc_profile_get_protocol (profile1);
+ g_assert (protocol);
+ g_assert (0 == strcmp ("testproto", mc_protocol_get_name (protocol)));
+ profile2 = mc_profile_lookup ("testprofile");
+ g_assert (profile1 == profile2);
+
+ mc_profile_free (profile1);
+ mc_profile_free (profile2);
+}
+
+void test_profile_list ()
+{
+ GList *list, *i;
+ McProfile *profile1, *profile2;
+
+ list = mc_profiles_list ();
+ g_assert (3 == g_list_length (list));
+ i = list;
+ profile1 = (McProfile *) i->data;
+ i = i->next;
+ profile2 = (McProfile *) i->data;
+ g_assert (0 == strcmp ("jabber",
+ mc_profile_get_unique_name (profile1)));
+ g_assert (0 == strcmp ("google-talk",
+ mc_profile_get_unique_name (profile2)));
+ g_assert (0 == strcmp ("testprofile",
+ mc_profile_get_unique_name ((McProfile *) i->next->data)));
+
+ mc_profiles_free_list (list);
+
+ list = mc_profiles_list ();
+ g_assert (3 == g_list_length (list));
+ i = list;
+ g_assert (profile1 == (McProfile *) i->data);
+ i = i->next;
+ g_assert (profile2 == (McProfile *) i->data);
+
+ mc_profiles_free_list (list);
+}
+
+void test_profile_stat ()
+{
+ McProfile *profile1, *profile2;
+
+ profile1 = mc_profile_lookup ("jabber");
+ utime ("../test/jabber.profile", NULL);
+ profile2 = mc_profile_lookup("jabber");
+ g_assert (profile1 != profile2);
+}
+
+void check_account_param (gpointer key, gpointer value, gpointer data)
+{
+ if (0 == strcmp (key, "account"))
+ {
+ g_assert (G_VALUE_HOLDS_STRING (value));
+ g_assert (0 == strcmp ("daf@foo", g_value_get_string (value)));
+ return;
+ }
+
+ if (0 == strcmp (key, "password"))
+ {
+ g_assert (G_VALUE_HOLDS_STRING (value));
+ g_assert (0 == strcmp ("badger", g_value_get_string (value)));
+ return;
+ }
+
+ g_warning ("got unexpected parameter \"%s\" for account", (gchar *) key);
+}
+
+void test_account()
+{
+ McAccount *account1, *account2;
+
+ account1 = mc_account_lookup ("jabber1");
+ g_assert (account1);
+ g_assert (0 == strcmp ("jabber1", mc_account_get_unique_name (account1)));
+ account2 = mc_account_lookup ("jabber1");
+ g_assert (account2);
+ g_assert (account1 == account2);
+
+ g_assert (mc_account_set_param_string(account1, "account", "daf@foo"));
+ g_assert (mc_account_set_param_string(account1, "password", "badger"));
+
+ g_hash_table_foreach(
+ mc_account_get_params(account1), check_account_param, account1);
+
+ mc_account_free(account1);
+ mc_account_free(account2);
+}
+
+void print_accounts_list ()
+{
+ GList *i, *accounts;
+
+ accounts = mc_accounts_list ();
+
+ for (i = accounts; NULL != i; i = i->next)
+ {
+ McAccount *account = (McAccount *) i->data;
+ const gchar *name = mc_account_get_unique_name (account);
+ const gchar *display_name = mc_account_get_display_name (account);
+
+ if (display_name)
+ g_print (" %s (\"%s\")\n", name, display_name);
+ else
+ g_print (" %s\n", name);
+ }
+}
+
+gint account_has_name (gconstpointer account_p, gconstpointer name_p)
+{
+ McAccount *account = (McAccount *) account_p;
+ const gchar *name = (gchar *) name_p;
+
+ return strcmp (mc_account_get_unique_name (account), name);
+}
+
+void test_mc_account_list ()
+{
+ GList *accounts;
+ McAccount *account;
+ McProfile *profile;
+ const gchar *name;
+
+ profile = mc_profile_lookup ("jabber");
+ account = mc_account_create (profile);
+ sleep(1);
+ while (g_main_context_iteration (NULL, FALSE));
+ name = mc_account_get_unique_name (account);
+ accounts = mc_accounts_list ();
+ g_assert (NULL != g_list_find_custom (accounts, name, account_has_name));
+ mc_accounts_list_free (accounts);
+ mc_account_delete (account);
+}
+
+void cb_account_created(McAccountMonitor *monitor, gchar *name, gpointer data)
+{
+ GSList **created = (GSList **) data;
+ *created = g_slist_append (*created, g_strdup (name));
+ /*printf ("account created: %s\n", name); */
+}
+
+void cb_account_deleted(McAccountMonitor *monitor, gchar *name, gpointer data)
+{
+ GSList **deleted = (GSList **) data;
+ *deleted = g_slist_append (*deleted, g_strdup (name));
+ /*printf ("account deleted: %s\n", name); */
+}
+
+void cb_account_enabled (McAccountMonitor *monitor, gchar *name, gpointer data)
+{
+ GSList **enabled = (GSList **) data;
+ *enabled = g_slist_append (*enabled, g_strdup (name));
+ /* printf ("account enabled: %s\n", name); */
+}
+
+void cb_account_disabled (McAccountMonitor *monitor, gchar *name, gpointer data)
+{
+ GSList **disabled = (GSList **) data;
+ *disabled = g_slist_append (*disabled, g_strdup (name));
+ /* printf ("account disabled: %s\n", name); */
+}
+
+void cb_account_changed (McAccountMonitor *monitor, gchar *name, gpointer data)
+{
+ GSList **disabled = (GSList **) data;
+ *disabled = g_slist_append (*disabled, g_strdup (name));
+}
+
+void test_account_monitor()
+{
+ McAccountMonitor *monitor;
+ McProfile *profile1, *profile2;
+ McAccount *account1, *account2;
+ GSList *created = NULL;
+ GSList *deleted = NULL;
+ GSList *enabled = NULL;
+ GSList *disabled = NULL;
+ GSList *changed = NULL;
+ const gchar *name1, *name2;
+
+ monitor = mc_account_monitor_new ();
+ g_signal_connect (monitor, "account-created", (GCallback) cb_account_created, &created);
+ g_signal_connect (monitor, "account-deleted", (GCallback) cb_account_deleted, &deleted);
+ g_signal_connect (monitor, "account-enabled", (GCallback) cb_account_enabled, &enabled);
+ g_signal_connect (monitor, "account-disabled", (GCallback) cb_account_disabled, &disabled);
+ g_signal_connect (monitor, "account-changed", (GCallback) cb_account_changed, &changed);
+
+ profile1 = mc_profile_lookup ("jabber");
+ g_assert (NULL != profile1);
+ g_assert (NULL != mc_profile_get_protocol (profile1));
+
+ profile2 = mc_profile_lookup ("google-talk");
+ g_assert (NULL != mc_profile_get_protocol (profile2));
+ g_assert (NULL != profile2);
+
+ /* test 1: creating */
+
+ account1 = mc_account_create (profile1);
+ name1 = mc_account_get_unique_name (account1);
+ /* printf ("new account: %s\n", name1);*/
+
+ account2 = mc_account_create (profile2);
+ name2 = mc_account_get_unique_name (account2);
+ /* printf ("new account: %s\n", name2); */
+
+ sleep(1);
+ while (g_main_context_iteration (NULL, FALSE));
+
+ g_assert (2 == g_slist_length (created));
+ g_assert (0 == g_slist_length (deleted));
+ g_assert (2 == g_slist_length (enabled));
+ g_assert (0 == g_slist_length (disabled));
+ g_assert (0 < g_slist_length (changed));
+
+ g_assert (NULL != g_slist_find_custom (created, name1, (GCompareFunc) strcmp));
+ g_assert (NULL != g_slist_find_custom (created, name2, (GCompareFunc) strcmp));
+
+ g_assert (NULL != g_slist_find_custom (enabled, name1, (GCompareFunc) strcmp));
+ g_assert (NULL != g_slist_find_custom (enabled, name2, (GCompareFunc) strcmp));
+
+ created = deleted = enabled = disabled = changed = NULL;
+
+ /* test 2: disabling */
+
+ mc_account_set_enabled (account1, FALSE);
+ mc_account_set_enabled (account2, FALSE);
+
+ sleep(1);
+ while (g_main_context_iteration (NULL, FALSE));
+
+ g_assert (0 == g_slist_length (created));
+ g_assert (0 == g_slist_length (deleted));
+ g_assert (0 == g_slist_length (enabled));
+ g_assert (2 == g_slist_length (disabled));
+ g_assert (0 == g_slist_length (changed));
+
+ g_assert (NULL != g_slist_find_custom (disabled, name1, (GCompareFunc) strcmp));
+ g_assert (NULL != g_slist_find_custom (disabled, name2, (GCompareFunc) strcmp));
+
+ created = deleted = enabled = disabled = changed = NULL;
+
+ /* test 3: re-enabling */
+
+ mc_account_set_enabled (account1, TRUE);
+ mc_account_set_enabled (account2, TRUE);
+
+ sleep(1);
+ while (g_main_context_iteration (NULL, FALSE));
+
+ g_assert (0 == g_slist_length (created));
+ g_assert (0 == g_slist_length (deleted));
+ g_assert (2 == g_slist_length (enabled));
+ g_assert (0 == g_slist_length (disabled));
+ g_assert (0 == g_slist_length (changed));
+
+ g_assert (NULL != g_slist_find_custom (enabled, name1, (GCompareFunc) strcmp));
+ g_assert (NULL != g_slist_find_custom (enabled, name2, (GCompareFunc) strcmp));
+
+ created = deleted = enabled = disabled = changed = NULL;
+
+ /* test 4: deleting */
+
+ mc_account_delete (account2);
+ mc_account_delete (account1);
+
+ sleep(1);
+ while (g_main_context_iteration (NULL, FALSE));
+
+ g_assert (0 == g_slist_length (created));
+ g_assert (2 == g_slist_length (deleted));
+ g_assert (0 == g_slist_length (enabled));
+ g_assert (2 == g_slist_length (disabled));
+ g_assert (0 < g_slist_length (changed));
+
+
+ g_assert (NULL != g_slist_find_custom (deleted, name1, (GCompareFunc) strcmp));
+ g_assert (NULL != g_slist_find_custom (deleted, name2, (GCompareFunc) strcmp));
+
+ mc_profile_free (profile1);
+ mc_profile_free (profile2);
+ mc_account_free (account1);
+ mc_account_free (account2);
+ g_object_unref (monitor);
+}
+
+void test_manager()
+{
+ McManager *manager1, *manager2;
+
+ manager1 = mc_manager_lookup ("testmanager");
+ g_assert (manager1);
+ g_assert (0 ==
+ strcmp ("testmanager", mc_manager_get_unique_name (manager1)));
+
+ g_assert (0 == strcmp ("testmanager",
+ mc_manager_get_unique_name (manager1)));
+ g_assert (0 == strcmp ("org.freedesktop.Telepathy.ConnectionManager.test",
+ mc_manager_get_bus_name (manager1)));
+ g_assert (0 == strcmp ("/org/freedesktop/Telepathy/ConnectionManager/test",
+ mc_manager_get_object_path (manager1)));
+
+ manager2 = mc_manager_lookup ("testmanager");
+ g_assert (manager2);
+ g_assert (manager1 == manager2);
+
+ mc_manager_free (manager1);
+ mc_manager_free (manager2);
+}
+
+void test_protocol ()
+{
+ McManager *manager1, *manager2;
+ McProtocol *protocol1, *protocol2;
+ GSList *params;
+ McProtocolParam expected_params[] = {
+ {"account", "s", NULL,
+ MC_PROTOCOL_PARAM_REQUIRED | MC_PROTOCOL_PARAM_REGISTER},
+ {"password", "s", NULL,
+ MC_PROTOCOL_PARAM_REQUIRED | MC_PROTOCOL_PARAM_REGISTER},
+ {"server", "s", NULL,
+ MC_PROTOCOL_PARAM_REQUIRED},
+ {"port", "q", NULL, 0},
+ {"register", "b", NULL, 0},
+ {NULL, NULL, NULL, 0}
+ }, *i;
+
+ manager1 = mc_manager_lookup ("testmanager");
+ manager2 = mc_manager_lookup ("testmanager");
+ protocol1 = mc_protocol_lookup (manager1, "testproto");
+ protocol2 = mc_protocol_lookup (manager2, "testproto");
+ g_assert (protocol1 == protocol2);
+
+ params = mc_protocol_get_params (protocol1);
+
+ for (i = expected_params; i->name; i++)
+ {
+ GSList *j;
+ gboolean found = FALSE;
+
+ for (j = params; j; j = j->next)
+ {
+ McProtocolParam *p = (McProtocolParam *) j->data;
+
+ if (0 == strcmp (i->name, p->name))
+ {
+ found = TRUE;
+ g_assert (0 == strcmp (i->name, p->name));
+ g_assert (0 == strcmp (i->signature, p->signature));
+ }
+ }
+
+ g_assert (found);
+ }
+
+ mc_protocol_free_params_list (params);
+
+ mc_manager_free (manager1);
+ mc_manager_free (manager2);
+ mc_protocol_free (protocol1);
+ mc_protocol_free (protocol2);
+}
+
+int main ()
+{
+ g_setenv ("MC_PROFILE_DIR", "../test", FALSE);
+ g_setenv ("MC_MANAGER_DIR", "../test", FALSE);
+
+ g_type_init ();
+
+ mc_make_resident ();
+ mc_make_resident ();
+
+ test_profile ();
+ test_profile_list ();
+ test_profile_stat ();
+ test_account ();
+ test_mc_account_list ();
+
+ /* this is a hack to workaround an apparent race condition when catching
+ * GConf signals in the process that caused them */
+ sleep(1);
+ while (g_main_context_iteration (NULL, FALSE));
+
+ test_account_monitor ();
+ test_manager ();
+ test_protocol ();
+
+ mc_profile_clear_cache ();
+ mc_account_clear_cache ();
+ mc_manager_clear_cache ();
+
+ return 0;
+}
+
+
diff --git a/mission-control.pc.in b/mission-control.pc.in
new file mode 100644
index 00000000..b51645dd
--- /dev/null
+++ b/mission-control.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+pluginlibdir=@pluginlibdir@
+
+Name: mission-control
+Description: Mission control filters interface library
+Version: @VERSION@
+Libs: -L${libdir} -lmissioncontrol-server
+Cflags: -I${includedir}/mission-control
+
diff --git a/server/Makefile.am b/server/Makefile.am
new file mode 100644
index 00000000..0f0a862c
--- /dev/null
+++ b/server/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = $(DBUS_CFLAGS) $(TELEPATHY_CFLAGS) -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ -DMC_DISABLE_DEPRECATED \
+ -DLIBDIR="@libdir@" -DLIBVERSION="0"
+
+if HAVE_SERVER
+
+servicefiledir=$(prefix)/share/dbus-1/services
+servicefile_DATA=org.freedesktop.Telepathy.MissionControl.service
+
+bin_PROGRAMS = mission-control
+mission_control_SOURCES = mc-server.c
+mission_control_LDADD = $(top_srcdir)/src/libmissioncontrol-server.la
+
+endif
diff --git a/server/mc-server.c b/server/mc-server.c
new file mode 100644
index 00000000..2d5117b8
--- /dev/null
+++ b/server/mc-server.c
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+#include "mcd-service.h"
+
+
+static void
+on_abort (McdService * mcd)
+{
+ g_debug ("Exiting now ...");
+
+ mcd_debug_print_tree (mcd);
+
+ g_object_unref (mcd);
+ g_debug ("MC now exits .. bye bye");
+ exit (0);
+}
+
+int
+main (int argc, char **argv)
+{
+ McdService *mcd;
+
+ g_type_init ();
+
+
+ mcd = mcd_service_new ();
+
+ /* Listen for suicide notification */
+ g_signal_connect_after (mcd, "abort", G_CALLBACK (on_abort), mcd);
+
+ /* connect */
+ mcd_mission_connect (MCD_MISSION (mcd));
+
+ mcd_service_run (MCD_OBJECT (mcd));
+
+ return 0;
+}
diff --git a/server/org.freedesktop.Telepathy.MissionControl.service.in b/server/org.freedesktop.Telepathy.MissionControl.service.in
new file mode 100644
index 00000000..9ac6d7ac
--- /dev/null
+++ b/server/org.freedesktop.Telepathy.MissionControl.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.Telepathy.MissionControl
+Exec=@prefix@/bin/mission-control
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 00000000..45d61e55
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,110 @@
+INCLUDES = $(GCONF_CFLAGS) $(TELEPATHY_CFLAGS) \
+ -DMCD_DEFAULT_FILTER_PLUGIN_DIR=\"@pluginlibdir@\" \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ -DMC_DISABLE_DEPRECATED -I$(top_srcdir) \
+ -O0 -g -fno-omit-frame-pointer -Wall -Werror
+
+mission_control_includedir = $(includedir)/mission-control
+mission_control_include = \
+ mcd-debug.h \
+ mcd-mission.h \
+ mcd-operation.h \
+ mcd-master.h \
+ mcd-controller.h \
+ mcd-manager.h \
+ mcd-connection.h \
+ mcd-presence-frame.h \
+ mcd-channel.h \
+ mcd-proxy.h \
+ mcd-dispatcher.h \
+ mcd-dispatcher-context.h \
+ mcd-service.h \
+ mcd-chan-handler.h
+
+mission_control_include_HEADERS = \
+ $(mission_control_include) \
+ mcd-enum-types.c \
+ mcd-enum-types.h
+
+BUILT_SOURCES = \
+ mcd-service-gen.h \
+ mcd-signals-marshal.h \
+ mcd-signals-marshal.c \
+ mcd-enum-types.c \
+ mcd-enum-types.h \
+ stamp-mcd-enum-types.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+lib_LTLIBRARIES = libmissioncontrol-server.la
+
+libmissioncontrol_server_la_LIBADD = $(GCONF_LIBS) $(TELEPATHY_LIBS) \
+ $(top_builddir)/libmissioncontrol/libmissioncontrol-config.la
+
+# we want to export symbols so that the plugins can see them
+libmissioncontrol_server_la_LDFLAGS = -export-dynamic
+
+libmissioncontrol_server_la_SOURCES = \
+ mcd-debug.c \
+ mcd-enum-types.c \
+ mcd-signals-marshal.c \
+ mcd-mission.c \
+ mcd-operation.c \
+ mcd-controller.c \
+ mcd-master.c \
+ mcd-manager.c \
+ mcd-connection.c \
+ mcd-presence-frame.c \
+ mcd-dispatcher.c \
+ mcd-channel.c \
+ mcd-service-gen.h \
+ mcd-service.c \
+ mcd-proxy.c \
+ mcd-chan-handler.c
+
+# bin_PROGRAMS = mission-control
+# mission_control_LDFLAGS = -export-dynamic
+#
+# mission_control_LDADD = $(GCONF_LIBS) $(TELEPATHY_LIBS) \
+# $(top_builddir)/libmissioncontrol/libmissioncontrol-config.la \
+# libmissioncontrol-server.la
+#
+# mission_control_SOURCES = \
+# mcd-main.c
+
+%-signals-marshal.h: %-signals-marshal.list Makefile
+ glib-genmarshal --header --prefix=$(subst -,_,$*)_marshal $< > $*-signals-marshal.h
+
+%-signals-marshal.c: %-signals-marshal.list Makefile
+ glib-genmarshal --body --prefix=$(subst -,_,$*)_marshal $< > $*-signals-marshal.c
+
+mcd-enum-types.h: stamp-mcd-enum-types.h
+ @true
+stamp-mcd-enum-types.h: Makefile $(mission_control_include) mcd-enum-types.c
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#ifndef __MCD_ENUM_TYPES_H__\n#define __MCD_ENUM_TYPES_H__\n\n#include \"mcd-mission.h\"\n#include \"mcd-channel.h\"\n\nG_BEGIN_DECLS\n" \
+ --fprod "/* enumerations from \"@filename@\" */\n" \
+ --vhead "GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define MCD_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
+ --ftail "G_END_DECLS\n\n#endif /* __MCD_ENUM_TYPES_H__ */" \
+ $(mission_control_include) ) >> xgen-geth \
+ && (cmp -s xgen-geth mcd-enum-types.h || cp xgen-geth mcd-enum-types.h ) \
+ && rm -f xgen-geth \
+ && echo timestamp > $(@F)
+
+mcd-enum-types.c: Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#include \"mcd-enum-types.h\"\n#define g_intern_static_string(s) (s)\n" \
+ --fprod "\n/* enumerations from \"@filename@\" */" \
+ --ftail "\n#define __MCD_ENUM_TYPES_C__\n" \
+ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (g_intern_static_string (\"@EnumName@\"), values);\n }\n return etype;\n}\n" \
+ $(mission_control_include) ) > xgen-getc \
+ && cp xgen-getc mcd-enum-types.c \
+ && rm -f xgen-getc
+
+
+mcd-service-gen.h: ../xml/mcd-dbus-services.xml
+ dbus-binding-tool --mode=glib-server --prefix=mcd_service $< > $@
+
+EXTRA_DIST = mcd-signals-marshal.list stamp-mcd-enum-types.h
diff --git a/src/mcd-chan-handler.c b/src/mcd-chan-handler.c
new file mode 100644
index 00000000..9c2fbf33
--- /dev/null
+++ b/src/mcd-chan-handler.c
@@ -0,0 +1,158 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "mcd-chan-handler.h"
+#include <config.h>
+
+#define FILE_SEPARATOR ','
+#define CH_FILE_SUFFIX ".chandler"
+#define CH_FILE_CH_GROUP "ChannelHandler"
+
+static void
+_mcd_channel_handler_free (McdChannelHandler *handler)
+{
+ g_free((gpointer) handler->bus_name);
+ g_free((gpointer) handler->obj_path);
+ g_free(handler);
+}
+
+static inline void
+_mcd_channel_handler_packer(GHashTable *handlers, gchar **string_list,
+ gsize list_length, gchar *bus_name,
+ TelepathyChannelMediaCapability capabilities,
+ gchar *object_path)
+{
+ gint i;
+ McdChannelHandler *handler;
+
+ for (i = 0; i < list_length; i++)
+ {
+ handler = g_new(McdChannelHandler, 1);
+ handler->bus_name = bus_name;
+ handler->obj_path = object_path;
+ handler->capabilities = capabilities;
+ g_hash_table_insert(handlers, g_strdup(string_list[i]), handler);
+ }
+}
+
+/*
+* Read files from configuration file directory.
+* This is used for Connection Manager and Channel Handler files.
+*/
+static void
+_mcd_channel_handlers_read_conf_files (GHashTable *handlers,
+ gchar *suffix, gchar *group)
+{
+ GError *error = NULL;
+ GKeyFile *file;
+ gchar **string_list;
+ gsize len;
+ GDir *dir;
+ const gchar *filename, *dirname;
+ gchar *absolute_filepath;
+ gchar *bus_name, *object_path;
+ TelepathyChannelMediaCapability capabilities;
+
+ dirname = g_getenv ("MC_CHANDLERS_DIR");
+ if (dirname == NULL)
+ dirname = CHANDLERS_DIR;
+
+ /* Read the configuration file directory */
+ if ((dir = g_dir_open(dirname, 0, &error)) == NULL)
+ {
+ g_error ("Error opening directory %s: %s", dirname,
+ error->message);
+ }
+
+ while ((filename = g_dir_read_name(dir)) != NULL)
+ {
+ /* Skip the file if it doesn't contain the required file suffix */
+ if (g_str_has_suffix(filename, suffix))
+ {
+ absolute_filepath = g_build_filename(dirname, filename, NULL);
+
+ file = g_key_file_new();
+ if (!g_key_file_load_from_file
+ (file, absolute_filepath, G_KEY_FILE_NONE, &error))
+ {
+ g_error ("%s", error->message);
+ }
+ g_key_file_set_list_separator(file, FILE_SEPARATOR);
+
+ if (!(bus_name = g_key_file_get_string (file, group,
+ "BusName", &error)))
+ {
+ g_error ("%s: %s", absolute_filepath, error->message);
+ }
+ if (!(object_path = g_key_file_get_string(file, group,
+ "ObjectPath", &error)))
+ {
+ g_error ("%s: %s", absolute_filepath, error->message);
+ }
+ capabilities = g_key_file_get_integer(file, group, "TypeSpecificCapabilities",
+ &error);
+ if (error)
+ {
+ if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+ g_warning ("%s: Error parsing %s: %s",
+ G_STRFUNC, filename, error->message);
+ g_error_free(error);
+ error = NULL;
+ capabilities = 0;
+ }
+
+
+ if (!(string_list = g_key_file_get_string_list(file, group, "ChannelType",
+ &len, &error)))
+ {
+ g_error ("%s: %s", absolute_filepath, error->message);
+ }
+
+ _mcd_channel_handler_packer(handlers, string_list, len, bus_name,
+ capabilities, object_path);
+
+ g_strfreev(string_list);
+ g_key_file_free(file);
+ g_free(absolute_filepath);
+ }
+ }
+ g_dir_close(dir);
+}
+
+GHashTable*
+mcd_get_channel_handlers (void)
+{
+ GHashTable *handlers;
+
+ handlers = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free,
+ (GDestroyNotify)_mcd_channel_handler_free);
+
+ /* Read Channel Handler files */
+ _mcd_channel_handlers_read_conf_files (handlers,
+ CH_FILE_SUFFIX, CH_FILE_CH_GROUP);
+ return handlers;
+}
diff --git a/src/mcd-chan-handler.h b/src/mcd-chan-handler.h
new file mode 100644
index 00000000..5c7f2d60
--- /dev/null
+++ b/src/mcd-chan-handler.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_CHAN_HANDLER_H
+#define MCD_CHAN_HANDLER_H
+
+#include <glib.h>
+#include <libtelepathy/tp-constants.h>
+
+/* Channel handler */
+
+typedef struct
+{
+ const gchar *bus_name;
+ const gchar *obj_path;
+ TelepathyChannelMediaCapability capabilities;
+} McdChannelHandler;
+
+GHashTable* mcd_get_channel_handlers (void);
+
+#endif
diff --git a/src/mcd-channel.c b/src/mcd-channel.c
new file mode 100644
index 00000000..b72001bf
--- /dev/null
+++ b/src/mcd-channel.c
@@ -0,0 +1,796 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib/gi18n.h>
+#include <libtelepathy/tp-chan-iface-group-gen.h>
+#include <libtelepathy/tp-constants.h>
+#include <libtelepathy/tp-conn.h>
+
+#include "mcd-channel.h"
+#include "mcd-enum-types.h"
+
+#define MCD_CHANNEL_PRIV(channel) (G_TYPE_INSTANCE_GET_PRIVATE ((channel), \
+ MCD_TYPE_CHANNEL, \
+ McdChannelPrivate))
+
+G_DEFINE_TYPE (McdChannel, mcd_channel, MCD_TYPE_MISSION);
+
+typedef struct _McdChannelPrivate
+{
+ /* Channel info */
+ gchar *channel_object_path;
+ gchar *channel_type;
+ GQuark channel_type_quark;
+ guint channel_handle;
+ TelepathyHandleType channel_handle_type;
+ gboolean outgoing;
+
+ /* Channel created based on the above channel info */
+ TpChan *tp_chan;
+
+ /* Pending members */
+ GArray *pending_local_members;
+ gboolean members_accepted;
+
+ McdChannelStatus status;
+ gchar *channel_name;
+
+ /* Requestor info */
+ guint requestor_serial;
+ gchar *requestor_client_id;
+
+ gboolean is_disposed;
+
+} McdChannelPrivate;
+
+enum _McdChannelSignalType
+{
+ STATUS_CHANGED,
+ MEMBERS_ACCEPTED,
+ LAST_SIGNAL
+};
+
+enum _McdChannelPropertyType
+{
+ PROP_CONNECTION=1,
+ PROP_TP_CHANNEL,
+ PROP_CHANNEL_STATUS,
+ PROP_CHANNEL_OBJECT_PATH,
+ PROP_CHANNEL_TYPE,
+ PROP_CHANNEL_TYPE_QUARK,
+ PROP_CHANNEL_HANDLE,
+ PROP_CHANNEL_HANDLE_TYPE,
+ PROP_OUTGOING,
+ PROP_REQUESTOR_SERIAL,
+ PROP_REQUESTOR_CLIENT_ID
+};
+
+static guint mcd_channel_signals[LAST_SIGNAL] = { 0 };
+
+static void _mcd_channel_release_tp_channel (McdChannel *channel,
+ gboolean close_channel);
+
+static void
+on_channel_members_changed (DBusGProxy * group_proxy,
+ const gchar * message, GArray * added,
+ GArray * removed, GArray * l_pending,
+ GArray * r_pending, guint actor,
+ guint reason, gpointer userdata)
+{
+ McdChannel *channel = MCD_CHANNEL (userdata);
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (userdata);
+ /* Local pending members? Add to the array and exit. */
+
+ if (l_pending && l_pending->len > 0)
+ {
+ int i;
+ /* FIXME: Add duplicity check */
+ for (i = 0; i < l_pending->len; i++)
+ {
+ g_array_append_val (priv->pending_local_members,
+ (guint) g_array_index (l_pending, guint, i));
+ g_debug ("Added handle %u to channel pending members",
+ (guint) g_array_index (l_pending, guint, i));
+ }
+ }
+
+ /* Added members? If any of them are in the local pending array, we can
+ * remove the lock restoration flag */
+
+ if (added && added->len > 0)
+ {
+ int i, j;
+ g_debug ("%u added members", added->len);
+ for (i = 0; i < added->len; i++)
+ {
+ guint added_member = g_array_index (added, guint, i);
+
+ /* N^2 complexity is not good, however with VOIP calls we should
+ * not bump into significant number of members */
+
+ for (j = 0; j < priv->pending_local_members->len; j++)
+ {
+ if (added_member ==
+ g_array_index (priv->pending_local_members, guint, i))
+ {
+ g_debug
+ ("Pending local member added -> do not restore lock");
+ g_debug
+ ("This should appear only when the call was accepted");
+ /* mcd_object_get ()->filters_unlocked_tk_lock = FALSE; */
+ priv->members_accepted = TRUE;
+ g_signal_emit_by_name (channel, "members-accepted");
+ break;
+ }
+ }
+ }
+ }
+ /* FIXME: We should also remove members from the local pending
+ * array, even if we don't need the info */
+}
+
+static void
+get_local_pending_cb (DBusGProxy * group_proxy,
+ GArray * l_pending, GError * error, gpointer userdata)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (userdata);
+ if (l_pending)
+ {
+ int i;
+ g_debug ("%u local pending members, adding", l_pending->len);
+ /* FIXME: Add duplicity check */
+ for (i = 0; i < l_pending->len; i++)
+ {
+ g_array_append_val (priv->pending_local_members,
+ (guint) g_array_index (l_pending, guint, i));
+ g_debug ("Added handle %u to channel pending members",
+ (guint) g_array_index (l_pending, guint, i));
+ }
+ g_array_free (l_pending, TRUE);
+ }
+}
+
+/* The callback is called on channel Closed signal */
+void
+on_tp_channel_closed (DBusGProxy * tp_chan, gpointer userdata)
+{
+ McdChannel *channel = MCD_CHANNEL (userdata);
+
+ _mcd_channel_release_tp_channel (channel, FALSE);
+ mcd_mission_abort (MCD_MISSION (channel));
+ g_debug ("Channel closed");
+}
+
+static void proxy_destroyed (DBusGProxy *tp_chan, McdChannel *channel)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (channel);
+
+ g_debug ("Channel proxy destroyed!");
+ g_object_unref (tp_chan);
+ priv->tp_chan = NULL;
+ mcd_mission_abort (MCD_MISSION (channel));
+ g_debug ("Channel closed");
+}
+
+static void
+_mcd_channel_release_tp_channel (McdChannel *channel, gboolean close_channel)
+{
+ DBusGProxy *group_iface;
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (channel);
+ if (priv->tp_chan)
+ {
+ GError *error = NULL;
+
+ g_debug ("%s: getting group_iface", G_STRFUNC);
+ group_iface = tp_chan_get_interface (priv->tp_chan,
+ TELEPATHY_CHAN_IFACE_GROUP_QUARK);
+ if (group_iface)
+ {
+ dbus_g_proxy_disconnect_signal (group_iface,"MembersChanged",
+ G_CALLBACK (on_channel_members_changed),
+ channel);
+ }
+
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_chan),
+ "Closed",
+ G_CALLBACK (on_tp_channel_closed),
+ channel);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (priv->tp_chan),
+ G_CALLBACK (proxy_destroyed),
+ channel);
+
+ if (close_channel && priv->channel_type_quark != TELEPATHY_CHAN_IFACE_CONTACTLIST_QUARK)
+ {
+ g_debug ("%s: Requesting telepathy to close the channel", G_STRFUNC);
+ tp_chan_close (DBUS_G_PROXY (priv->tp_chan), &error);
+ if (error)
+ {
+ g_warning ("%s: Request for channel close failed: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+ }
+ /* Destroy our proxy */
+ g_object_unref (priv->tp_chan);
+
+ priv->tp_chan = NULL;
+ }
+}
+
+static void
+_mcd_channel_set_property (GObject * obj, guint prop_id,
+ const GValue * val, GParamSpec * pspec)
+{
+ DBusGProxy *group_iface;
+ TpChan *tp_chan;
+ McdChannel *channel = MCD_CHANNEL (obj);
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_CHANNEL_STATUS:
+ priv->status = g_value_get_enum (val);
+ g_signal_emit_by_name (channel, "status-changed", priv->status);
+ break;
+ case PROP_CONNECTION:
+ break;
+ case PROP_TP_CHANNEL:
+ tp_chan = g_value_get_object (val);
+ if (tp_chan)
+ {
+ g_return_if_fail (priv->channel_object_path != NULL);
+ g_return_if_fail (priv->channel_type != NULL);
+ g_return_if_fail (priv->channel_handle >= 0);
+
+ /* FIXME: BUG in libtelepathy */
+ /* g_return_if_fail (TELEPATHY_IS_CHAN (tp_chan)); */
+ g_object_ref (tp_chan);
+ }
+ _mcd_channel_release_tp_channel (channel, TRUE);
+ priv->tp_chan = tp_chan;
+ if (priv->tp_chan)
+ {
+ group_iface = tp_chan_get_interface (priv->tp_chan,
+ TELEPATHY_CHAN_IFACE_GROUP_QUARK);
+ if (group_iface)
+ {
+ /* Setup channel watches */
+ dbus_g_proxy_connect_signal (group_iface, "MembersChanged",
+ G_CALLBACK (on_channel_members_changed),
+ channel, NULL);
+ tp_chan_iface_group_get_local_pending_members_async (group_iface,
+ get_local_pending_cb,
+ channel);
+ }
+ /* We want to track the channel object closes, because we need to do
+ * some cleanups when it's gone */
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_chan), "Closed",
+ G_CALLBACK (on_tp_channel_closed),
+ channel, NULL);
+ g_signal_connect (priv->tp_chan, "destroy",
+ G_CALLBACK (proxy_destroyed), channel);
+
+ }
+ break;
+ case PROP_CHANNEL_OBJECT_PATH:
+ /* g_return_if_fail (g_value_get_string (val) != NULL); */
+ g_free (priv->channel_object_path);
+ if (g_value_get_string (val) != NULL)
+ priv->channel_object_path = g_strdup (g_value_get_string (val));
+ else
+ priv->channel_object_path = NULL;
+ break;
+ case PROP_CHANNEL_TYPE:
+ /* g_return_if_fail (g_value_get_string (val) != NULL); */
+ g_free (priv->channel_type);
+ if (g_value_get_string (val) != NULL)
+ {
+ priv->channel_type = g_strdup (g_value_get_string (val));
+ priv->channel_type_quark = g_quark_from_string (priv->channel_type);
+ }
+ else
+ {
+ priv->channel_type = NULL;
+ priv->channel_type_quark = 0;
+ }
+ break;
+ case PROP_CHANNEL_TYPE_QUARK:
+ break;
+ case PROP_CHANNEL_HANDLE:
+ priv->channel_handle = g_value_get_uint (val);
+ break;
+ case PROP_CHANNEL_HANDLE_TYPE:
+ priv->channel_handle_type = g_value_get_uint (val);
+ break;
+ case PROP_OUTGOING:
+ priv->outgoing = g_value_get_boolean (val);
+ break;
+ case PROP_REQUESTOR_SERIAL:
+ priv->requestor_serial = g_value_get_uint (val);
+ break;
+ case PROP_REQUESTOR_CLIENT_ID:
+ g_free (priv->requestor_client_id);
+ priv->requestor_client_id = g_value_dup_string (val);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_channel_get_property (GObject * obj, guint prop_id,
+ GValue * val, GParamSpec * pspec)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_CONNECTION:
+ /* FIXME: This is presumetous and wrong */
+ g_value_set_object (val, mcd_mission_get_parent (MCD_MISSION (obj)));
+ break;
+ case PROP_CHANNEL_STATUS:
+ g_value_set_enum (val, priv->status);
+ break;
+ case PROP_TP_CHANNEL:
+ g_value_set_object (val, priv->tp_chan);
+ break;
+ case PROP_CHANNEL_OBJECT_PATH:
+ g_value_set_string (val, priv->channel_object_path);
+ break;
+ case PROP_CHANNEL_TYPE:
+ g_value_set_string (val, priv->channel_type);
+ break;
+ case PROP_CHANNEL_TYPE_QUARK:
+ g_value_set_uint (val, priv->channel_type_quark);
+ break;
+ case PROP_CHANNEL_HANDLE:
+ g_value_set_uint (val, priv->channel_handle);
+ break;
+ case PROP_CHANNEL_HANDLE_TYPE:
+ g_value_set_uint (val, priv->channel_handle_type);
+ break;
+ case PROP_OUTGOING:
+ g_value_set_boolean (val, priv->outgoing);
+ break;
+ case PROP_REQUESTOR_SERIAL:
+ g_value_set_uint (val, priv->requestor_serial);
+ break;
+ case PROP_REQUESTOR_CLIENT_ID:
+ g_value_set_string (val, priv->requestor_client_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_channel_finalize (GObject * object)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (object);
+
+ g_free (priv->channel_object_path);
+ g_free (priv->channel_type);
+ g_array_free (priv->pending_local_members, TRUE);
+ g_free (priv->requestor_client_id);
+ g_free (priv->channel_name);
+
+ G_OBJECT_CLASS (mcd_channel_parent_class)->finalize (object);
+}
+
+static void
+_mcd_channel_dispose (GObject * object)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (object);
+
+ if (priv->is_disposed)
+ return;
+
+ priv->is_disposed = TRUE;
+ _mcd_channel_release_tp_channel (MCD_CHANNEL (object), TRUE);
+ G_OBJECT_CLASS (mcd_channel_parent_class)->dispose (object);
+}
+
+static void
+mcd_channel_class_init (McdChannelClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McdChannelPrivate));
+
+ object_class->finalize = _mcd_channel_finalize;
+ object_class->dispose = _mcd_channel_dispose;
+ object_class->set_property = _mcd_channel_set_property;
+ object_class->get_property = _mcd_channel_get_property;
+
+ /* signals */
+ mcd_channel_signals[STATUS_CHANGED] =
+ g_signal_new ("status-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdChannelClass,
+ status_changed_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
+ 1, G_TYPE_INT);
+ mcd_channel_signals[MEMBERS_ACCEPTED] =
+ g_signal_new ("members-accepted", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdChannelClass,
+ members_accepted_signal),
+ NULL,
+ NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /* properties */
+ g_object_class_install_property (object_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ _ ("McdConnection Object"),
+ _ ("McdConnection Object from which this channel was created"),
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_TP_CHANNEL,
+ g_param_spec_object ("tp-channel",
+ _ ("Telepathy Channel Object"),
+ _ ("Telepathy Channel Object wrapped by it"),
+ TELEPATHY_CHAN_TYPE,
+ G_PARAM_READWRITE /* |
+ G_PARAM_CONSTRUCT_ONLY */));
+ g_object_class_install_property (object_class, PROP_CHANNEL_STATUS,
+ g_param_spec_enum ("channel-status",
+ _("Channel status"),
+ _("Channel status that indicates the state of channel"),
+ MCD_TYPE_CHANNEL_STATUS,
+ MCD_CHANNEL_PENDING,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_CHANNEL_OBJECT_PATH,
+ g_param_spec_string ("channel-object-path",
+ _ ("Channel dbus object path"),
+ _ ("DBus Bus name to use by us"),
+ NULL,
+ G_PARAM_READWRITE /*|
+ G_PARAM_CONSTRUCT_ONLY */));
+ g_object_class_install_property (object_class, PROP_CHANNEL_TYPE,
+ g_param_spec_string ("channel-type",
+ _ ("Channel type"),
+ _ ("Telepathy channel type"),
+ NULL,
+ G_PARAM_READWRITE /*|
+ G_PARAM_CONSTRUCT_ONLY*/));
+ g_object_class_install_property (object_class, PROP_CHANNEL_TYPE_QUARK,
+ g_param_spec_uint ("channel-type-quark",
+ _("Telepathy channel type in quark form"),
+ _("Telepathy channel type in quark form"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE /*|
+ G_PARAM_CONSTRUCT_ONLY*/));
+ g_object_class_install_property (object_class, PROP_CHANNEL_HANDLE,
+ g_param_spec_uint ("channel-handle",
+ _("Telepathy channel handle"),
+ _("Telepathy channel handle"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE /*|
+ G_PARAM_CONSTRUCT_ONLY */));
+ g_object_class_install_property (object_class, PROP_CHANNEL_HANDLE_TYPE,
+ g_param_spec_uint ("channel-handle-type",
+ _("Telepathy channel handle type"),
+ _("Telepathy channel handle type"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE /* |
+ G_PARAM_CONSTRUCT_ONLY */));
+ g_object_class_install_property (object_class, PROP_OUTGOING,
+ g_param_spec_boolean ("outgoing",
+ _("Outgoing channel"),
+ _("True if the channel was requested by us"),
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_REQUESTOR_SERIAL,
+ g_param_spec_uint ("requestor-serial",
+ _("Requestor serial number"),
+ _("Requestor serial number"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_REQUESTOR_CLIENT_ID,
+ g_param_spec_string ("requestor-client-id",
+ _("Requestor client id"),
+ _("Requestor client id"),
+ NULL, G_PARAM_READWRITE));
+}
+
+static void
+mcd_channel_init (McdChannel * obj)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (obj);
+ priv->pending_local_members = g_array_new (FALSE, FALSE,
+ sizeof (guint));
+}
+
+McdChannel *
+mcd_channel_new (TpChan * tp_chan, const gchar *channel_object_path,
+ const gchar *channel_type, guint channel_handle,
+ TelepathyHandleType channel_handle_type, gboolean outgoing,
+ guint requestor_serial, const gchar *requestor_client_id)
+{
+ McdChannel *obj;
+ obj = MCD_CHANNEL (g_object_new (MCD_TYPE_CHANNEL,
+ "channel-object-path", channel_object_path,
+ "channel-type", channel_type,
+ "channel-handle", channel_handle,
+ "channel-handle-type", channel_handle_type,
+ "outgoing", outgoing,
+ "requestor-serial", requestor_serial,
+ "requestor-client-id", requestor_client_id,
+ "tp-channel", tp_chan,
+ NULL));
+ return obj;
+}
+
+void
+mcd_channel_set_status (McdChannel *channel, McdChannelStatus status)
+{
+ g_return_if_fail(MCD_IS_CHANNEL(channel));
+ g_object_set (channel, "channel-status", status, NULL);
+}
+
+McdChannelStatus
+mcd_channel_get_status (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->status;
+}
+
+gboolean
+mcd_channel_get_members_accepted (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->members_accepted;
+}
+
+const gchar *
+mcd_channel_get_channel_type (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->channel_type;
+}
+
+GQuark
+mcd_channel_get_channel_type_quark (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->channel_type_quark;
+}
+
+const gchar *
+mcd_channel_get_object_path (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->channel_object_path;
+}
+
+guint
+mcd_channel_get_handle (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->channel_handle;
+}
+
+TelepathyHandleType
+mcd_channel_get_handle_type (McdChannel *channel)
+{
+ return MCD_CHANNEL_PRIV (channel)->channel_handle_type;
+}
+
+/* Similar to the another helper, but uses the array version (InspectHandles), free with g_strfreev*/
+static gchar **
+_contact_handles_to_strings (TpConn * conn, guint handle_type,
+ const GArray * handles)
+{
+ gchar **contact_addresses = NULL;
+ GError *error = NULL;
+
+ tp_conn_inspect_handles (DBUS_G_PROXY (conn), handle_type, handles,
+ &contact_addresses, &error);
+
+ if (error)
+ {
+ g_warning ("Error %s getting contacts for %u handles",
+ error->message, handles->len);
+ g_error_free (error);
+ }
+
+ return contact_addresses;
+}
+
+GPtrArray*
+mcd_channel_get_members (McdChannel *channel)
+{
+ GObject *connection;
+ TpConn *tp_connection;
+ GPtrArray *members = NULL;
+ gchar *contact_address;
+
+ g_return_val_if_fail(MCD_IS_CHANNEL(channel), NULL);
+ g_object_get (G_OBJECT (channel), "connection",
+ &connection, NULL);
+ g_object_get (connection, "tp-connection",
+ &tp_connection, NULL);
+
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (channel);
+
+ g_assert (priv->tp_chan != NULL);
+
+ g_debug ("Creating members list");
+ if (priv->channel_handle_type == TP_CONN_HANDLE_TYPE_CONTACT)
+ {
+ /* TODO: Now that we have only the multi-handle
+ * inspection call, we might be able to unify this
+ * and the case below */
+
+ gchar **addresses;
+ GArray *handles =
+ g_array_sized_new (FALSE, FALSE, sizeof (guint), 1);
+ g_debug ("Single contact");
+
+ g_array_insert_val (handles, 0,
+ priv->channel_handle);
+
+ addresses =
+ _contact_handles_to_strings (tp_connection,
+ priv->channel_handle_type,
+ handles);
+ g_array_free (handles, TRUE);
+ if (!addresses || !addresses[0])
+ {
+ g_warning ("Unable to get contact address");
+ }
+ else
+ {
+ contact_address = g_strdup (addresses[0]);
+ g_strfreev (addresses);
+ /*Creating the members array and adding contact_address there */
+ members = g_ptr_array_new ();
+ g_ptr_array_add (members, contact_address);
+ }
+ }
+
+ else /*Group channel */
+ {
+ DBusGProxy *group_proxy;
+ GArray *contact_handles = NULL;
+ GError *error = NULL;
+
+ g_debug ("Multiple contacts");
+
+ /* get a group proxy from the channel */
+ group_proxy = tp_chan_get_interface (priv->tp_chan,
+ TELEPATHY_CHAN_IFACE_GROUP_QUARK);
+
+ tp_chan_iface_group_get_members (DBUS_G_PROXY (group_proxy),
+ &contact_handles, &error);
+
+ if (error)
+ {
+ g_warning ("Unable to get group members: %s", error->message);
+ g_error_free (error);
+ }
+ else if (!contact_handles || !contact_handles->len)
+ {
+ g_warning ("No contact handles");
+ }
+ else
+ { /*Get the real user names */
+ gchar **contact_addresses;
+ int i;
+
+ members = g_ptr_array_new ();
+
+ g_debug ("Transforming %i contacts into strings",
+ contact_handles->len);
+
+ contact_addresses =
+ _contact_handles_to_strings (tp_connection,
+ TP_CONN_HANDLE_TYPE_CONTACT,
+ contact_handles);
+
+ if (contact_addresses)
+ {
+ for (i = 0; i < contact_handles->len; i++)
+ {
+ g_ptr_array_add (members,
+ g_strdup (contact_addresses[i]));
+ }
+ g_strfreev (contact_addresses);
+ }
+ else
+ {
+ g_warning ("Unable to get contact address(multi)");
+ }
+ }
+
+ if (contact_handles)
+ {
+ g_array_free (contact_handles, TRUE);
+ }
+ }
+
+ g_object_unref (connection);
+ g_object_unref (tp_connection);
+ return members;
+}
+
+/**
+ * mcd_channel_get_name:
+ * @channel: the #McdChannel.
+ *
+ * Get the Telepathy name of @channel (calls InspectHandles on the channel
+ * handle).
+ *
+ * Returns: a const string holding the channel name.
+ */
+const gchar *
+mcd_channel_get_name (McdChannel *channel)
+{
+ McdChannelPrivate *priv = MCD_CHANNEL_PRIV (channel);
+
+ if (!priv->channel_name)
+ {
+ GObject *connection = NULL;
+ TpConn *tp_conn = NULL;
+ GArray *request_handles;
+ gchar **handle_names = NULL;
+ GError *error = NULL;
+
+ request_handles = g_array_new (FALSE, FALSE, sizeof (guint));
+ g_array_append_val (request_handles, priv->channel_handle);
+
+ g_object_get (channel, "connection", &connection, NULL);
+ g_object_get (connection, "tp-connection", &tp_conn, NULL);
+ if (!tp_conn_inspect_handles (DBUS_G_PROXY (tp_conn),
+ priv->channel_handle_type,
+ request_handles,
+ &handle_names, &error))
+ {
+ g_warning ("%s: InspectHandles failed: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+ else
+ priv->channel_name = handle_names[0];
+
+ g_object_unref (connection);
+ g_object_unref (tp_conn);
+ g_array_free (request_handles, TRUE);
+ /* free only the pointer array, not the string itself */
+ g_free (handle_names);
+ }
+
+ return priv->channel_name;
+}
+
diff --git a/src/mcd-channel.h b/src/mcd-channel.h
new file mode 100644
index 00000000..c668e508
--- /dev/null
+++ b/src/mcd-channel.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_CHANNEL_H
+#define MCD_CHANNEL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-constants.h>
+
+#include "mcd-mission.h"
+
+G_BEGIN_DECLS
+
+#define MCD_TYPE_CHANNEL (mcd_channel_get_type ())
+#define MCD_CHANNEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_CHANNEL, McdChannel))
+#define MCD_CHANNEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_CHANNEL, McdChannelClass))
+#define MCD_IS_CHANNEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_CHANNEL))
+#define MCD_IS_CHANNEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_CHANNEL))
+#define MCD_CHANNEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_CHANNEL, McdChannelClass))
+
+typedef struct _McdChannel McdChannel;
+typedef struct _McdChannelClass McdChannelClass;
+
+typedef enum
+{
+ MCD_CHANNEL_PENDING, /* Telepathy channel is not yet created */
+ MCD_CHANNEL_DISPATCHING, /* Telepathy channel is created and waiting dispatch */
+ MCD_CHANNEL_DISPATCHED, /* Channel has been dispatched to handler */
+ MCD_CHANNEL_FAILED, /* Channel could not be dispached to handler, dying */
+
+} McdChannelStatus;
+
+struct _McdChannel
+{
+ McdMission parent;
+};
+
+struct _McdChannelClass
+{
+ McdMissionClass parent_class;
+
+ /* signals */
+ void (*status_changed_signal) (McdChannel * channel,
+ McdChannelStatus status);
+ void (*members_accepted_signal) (McdChannel *channel);
+};
+
+struct mcd_channel_request
+{
+ const gchar *account_name;
+ const gchar *channel_type;
+ guint channel_handle;
+ const gchar *channel_handle_string;
+ gint channel_handle_type;
+ guint requestor_serial;
+ const gchar *requestor_client_id;
+};
+
+GType mcd_channel_get_type (void);
+
+McdChannel *mcd_channel_new (TpChan *channel,
+ const gchar *channel_object_path,
+ const gchar *channel_type,
+ guint channel_handle,
+ TelepathyHandleType channel_handle_type,
+ gboolean outgoing,
+ guint requestor_serial,
+ const gchar *requestor_client_id);
+
+void mcd_channel_set_status (McdChannel *channel, McdChannelStatus status);
+McdChannelStatus mcd_channel_get_status (McdChannel * channel);
+gboolean mcd_channel_get_members_accepted (McdChannel *channel);
+const gchar* mcd_channel_get_channel_type (McdChannel *channel);
+GQuark mcd_channel_get_channel_type_quark (McdChannel *channel);
+const gchar* mcd_channel_get_object_path (McdChannel *channel);
+guint mcd_channel_get_handle (McdChannel *channel);
+TelepathyHandleType mcd_channel_get_handle_type (McdChannel *channel);
+gint mcd_channel_get_flags (McdChannel *channel);
+GPtrArray* mcd_channel_get_members (McdChannel *channel);
+const gchar *mcd_channel_get_name (McdChannel *channel);
+
+G_END_DECLS
+#endif /* MCD_CHANNEL_H */
diff --git a/src/mcd-connection.c b/src/mcd-connection.c
new file mode 100644
index 00000000..9d2c0e35
--- /dev/null
+++ b/src/mcd-connection.c
@@ -0,0 +1,1980 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sched.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include <libmissioncontrol/mc-manager.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-protocol.h>
+#include <libmissioncontrol/mc-profile.h>
+#include <libtelepathy/tp-connmgr.h>
+#include <libtelepathy/tp-interfaces.h>
+#include <libtelepathy/tp-constants.h>
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-conn.h>
+#include <libtelepathy/tp-conn-gen.h>
+#include <libtelepathy/tp-conn-iface-presence-gen.h>
+#include <libtelepathy/tp-conn-iface-capabilities-gen.h>
+#include <libtelepathy/tp-conn-iface-avatars-gen.h>
+#include <libtelepathy/tp-helpers.h>
+
+#include "mcd-connection.h"
+#include "mcd-channel.h"
+
+#define MAX_REF_PRESENCE 4
+
+#define MCD_CONNECTION_PRIV(mcdconn) (G_TYPE_INSTANCE_GET_PRIVATE ((mcdconn), \
+ MCD_TYPE_CONNECTION, \
+ McdConnectionPrivate))
+
+G_DEFINE_TYPE (McdConnection, mcd_connection, MCD_TYPE_OPERATION);
+
+/* Private */
+typedef struct
+{
+ /* DBUS connection */
+ DBusGConnection *dbus_connection;
+
+ /* DBus bus name */
+ gchar *bus_name;
+
+ /* Presence frame */
+ McdPresenceFrame *presence_frame;
+
+ /* Channel dispatcher */
+ McdDispatcher *dispatcher;
+
+ /* Account */
+ McAccount *account;
+
+ /* Associated profile */
+ /* McProfile *profile; */
+
+ /* Telepathy connection manager */
+ TpConnMgr *tp_conn_mgr;
+
+ /* Telepathy connection */
+ TpConn *tp_conn;
+
+ /* Presence proxy */
+ DBusGProxy *presence_proxy;
+
+ DBusGProxy *avatars_proxy;
+
+ /* Capabilities proxy */
+ DBusGProxy *capabilities_proxy;
+
+ /* Capabilities timer */
+ guint capabilities_timer;
+
+ guint reconnect_timer; /* timer for reconnection */
+ guint reconnect_interval;
+
+ /* Supported presences */
+ GArray *recognized_presence_info_array;
+ struct presence_info *presence_to_set[LAST_MC_PRESENCE - 1];
+
+ /* List of pending channels which has been requested to telepathy,
+ * but telepathy hasn't yet responded with the channel object
+ */
+ GHashTable *pending_channels;
+
+ TelepathyConnectionStatusReason abort_reason;
+ gboolean got_capabilities;
+
+ gboolean is_disposed;
+
+} McdConnectionPrivate;
+
+struct presence_info
+{
+ gchar *presence_str;
+ gboolean allow_message;
+};
+
+enum
+{
+ PROP_0,
+ PROP_DBUS_CONNECTION,
+ PROP_BUS_NAME,
+ PROP_TP_MANAGER,
+ PROP_TP_CONNECTION,
+ PROP_ACCOUNT,
+ PROP_PRESENCE_FRAME,
+ PROP_DISPATCHER,
+};
+
+/* This table lists the Telepathy well-known statuses and the corresponding
+ * McPresence values; the order in which the items appear is only important for
+ * those statuses which map to the same McPresence value: for them, the first
+ * ones will be preferred. */
+static const struct _presence_mapping {
+ gchar *presence_str;
+ McPresence mc_presence;
+} presence_mapping[] = {
+ { "offline", MC_PRESENCE_OFFLINE },
+ { "available", MC_PRESENCE_AVAILABLE },
+ { "away", MC_PRESENCE_AWAY },
+ { "xa", MC_PRESENCE_EXTENDED_AWAY },
+ { "hidden", MC_PRESENCE_HIDDEN },
+ { "dnd", MC_PRESENCE_DO_NOT_DISTURB },
+ { "brb", MC_PRESENCE_AWAY },
+ { "busy", MC_PRESENCE_DO_NOT_DISTURB },
+ { NULL, 0 },
+};
+
+static const McPresence fallback_presence
+ [LAST_MC_PRESENCE - 1][MAX_REF_PRESENCE] = {
+ { 0 }, /* MC_PRESENCE_OFFLINE */
+ { 0 }, /* MC_PRESENCE_AVAILABLE */
+ { MC_PRESENCE_AVAILABLE, 0 }, /* MC_PRESENCE_AWAY */
+ { MC_PRESENCE_AWAY, MC_PRESENCE_AVAILABLE, 0 }, /* MC_PRESENCE_EXTENDED_AWAY */
+ { MC_PRESENCE_DO_NOT_DISTURB, MC_PRESENCE_EXTENDED_AWAY, MC_PRESENCE_AVAILABLE, 0 }, /* MC_PRESENCE_HIDDEN */
+ { 0 } /* MC_PRESENCE_DO_NOT_DISTURB */
+};
+
+struct request_id {
+ guint requestor_serial;
+ const gchar *requestor_client_id;
+};
+
+struct capabilities_wait_data {
+ GError *error; /* error originally received when channel request failed */
+ McdChannel *channel;
+ McdConnectionPrivate *priv;
+};
+
+static void mcd_async_request_chan_callback (DBusGProxy *proxy,
+ gchar *channel_path,
+ GError *error,
+ gpointer user_data);
+static GError * map_tp_error_to_mc_error (McdChannel *channel, GError *tp_error);
+static void _mcd_connection_setup (McdConnection * connection);
+static void _mcd_connection_release_tp_connection (McdConnection *connection);
+
+static McPresence presence_str_to_enum (const gchar *presence_str)
+{
+ const struct _presence_mapping *mapping;
+ for (mapping = presence_mapping; mapping->presence_str; mapping++)
+ if (strcmp (presence_str, mapping->presence_str) == 0)
+ return mapping->mc_presence;
+ return MC_PRESENCE_UNSET;
+}
+
+/* Free dynamic members and presence_info itself */
+static void
+_mcd_connection_free_presence_info (McdConnection * conn)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (conn);
+
+ if (priv->recognized_presence_info_array != NULL)
+ {
+ struct presence_info *pi;
+ gint i;
+
+ for (i = 0; i < priv->recognized_presence_info_array->len; i++)
+ {
+ pi = &g_array_index (priv->recognized_presence_info_array,
+ struct presence_info, i);
+ g_free (pi->presence_str);
+ }
+ g_array_free (priv->recognized_presence_info_array, TRUE);
+ priv->recognized_presence_info_array = NULL;
+ }
+}
+
+/* Fill empty presence_to_set elements with fallback presence values */
+static void
+_mcd_connection_set_fallback_presences (McdConnection * connection, gint i)
+{
+ gint j;
+ McdConnectionPrivate *priv;
+
+ g_return_if_fail (MCD_IS_CONNECTION (connection));
+
+ priv = MCD_CONNECTION_PRIV (connection);
+
+ for (j = 0; j < MAX_REF_PRESENCE; j++)
+ {
+ struct presence_info *presence;
+
+ presence = priv->presence_to_set[fallback_presence[i][j] - 1];
+ if (presence != NULL)
+ {
+ priv->presence_to_set[i] = presence;
+ g_debug ("Fallback for McPresence %d set to %s",
+ i + 1, presence->presence_str);
+ return;
+ }
+ }
+}
+
+/* Used for initializing recognized_presence_info_array. */
+static void
+recognize_presence (gpointer key, gpointer value, gpointer user_data)
+{
+ guint telepathy_enum;
+ GHashTable *ht;
+ struct presence_info pi;
+ GValueArray *status;
+ McdConnectionPrivate *priv = (McdConnectionPrivate *) user_data;
+ gint j;
+
+ status = (GValueArray *) value;
+
+ /* Pull out the arguments of Telepathy GetStatuses */
+ ht = (GHashTable *) g_value_get_boxed (g_value_array_get_nth (status, 3));
+ pi.allow_message = g_hash_table_lookup (ht, "message") ? TRUE : FALSE;
+
+ /* Look up which MC_PRESENCE this presence string corresponds */
+ pi.presence_str = g_strdup ((const gchar *) key);
+
+ j = presence_str_to_enum (pi.presence_str);
+ if (j == MC_PRESENCE_UNSET)
+ {
+ /* Didn't find match by comparing strings so map using the telepathy enum. */
+ telepathy_enum = g_value_get_uint (g_value_array_get_nth (status, 0));
+ switch (telepathy_enum)
+ {
+ case TP_CONN_PRESENCE_TYPE_OFFLINE:
+ j = MC_PRESENCE_OFFLINE;
+ break;
+ case TP_CONN_PRESENCE_TYPE_AVAILABLE:
+ j = MC_PRESENCE_AVAILABLE;
+ break;
+ case TP_CONN_PRESENCE_TYPE_AWAY:
+ j = MC_PRESENCE_AWAY;
+ break;
+ case TP_CONN_PRESENCE_TYPE_EXTENDED_AWAY:
+ j = MC_PRESENCE_EXTENDED_AWAY;
+ break;
+ case TP_CONN_PRESENCE_TYPE_HIDDEN:
+ j = MC_PRESENCE_HIDDEN;
+ break;
+ default:
+ g_debug ("Unknown Telepathy presence type. Presence %s "
+ "with Telepathy enum %d ignored.", pi.presence_str,
+ telepathy_enum);
+ g_free (pi.presence_str);
+ return;
+ break;
+ }
+ }
+ g_array_append_val (priv->recognized_presence_info_array, pi);
+}
+
+static void
+enable_well_known_presences (McdConnectionPrivate *priv)
+{
+ const struct _presence_mapping *mapping;
+ struct presence_info *pi;
+
+ /* Loop the presence_mappinges; if one of the basic McPresences is not set,
+ * check if an mapping is supported by the connection and, if so, use it */
+ for (mapping = presence_mapping; mapping->presence_str; mapping++)
+ {
+ if (priv->presence_to_set[mapping->mc_presence - 1] == NULL)
+ {
+ gint i;
+ /* see if this presence is supported by the connection */
+ for (i = 0; i < priv->recognized_presence_info_array->len; i++)
+ {
+ pi = &g_array_index (priv->recognized_presence_info_array,
+ struct presence_info, i);
+ if (strcmp (pi->presence_str, mapping->presence_str) == 0)
+ {
+ g_debug ("Using %s status for McPresence %d",
+ mapping->presence_str, mapping->mc_presence);
+ /* Presence values used when setting the presence status */
+ priv->presence_to_set[mapping->mc_presence - 1] = pi;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void
+_mcd_connection_set_presence (McdConnection * connection,
+ McPresence presence,
+ const gchar * presence_message)
+{
+ const gchar *presence_str;
+ GHashTable *presence_ht;
+ GHashTable *params_ht;
+ struct presence_info *supported_presence_info;
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ GError *error = NULL;
+ GValue msg_gval = { 0, };
+
+ if (!priv->tp_conn)
+ {
+ _mcd_connection_setup (connection);
+ return;
+ }
+ g_return_if_fail (TELEPATHY_IS_CONN (priv->tp_conn));
+ g_return_if_fail (priv->bus_name != NULL);
+
+ if (priv->presence_proxy == NULL)
+ {
+ GHashTable *status_hash;
+ guint i;
+ GError *error = NULL;
+
+ /* Gets a reference to it */
+ priv->presence_proxy =
+ tp_conn_get_interface (priv->tp_conn,
+ TELEPATHY_CONN_IFACE_PRESENCE_QUARK);
+ if (priv->presence_proxy == NULL)
+ {
+ g_warning ("%s: Account %s has no presence interface", G_STRFUNC,
+ mc_account_get_unique_name (priv->account));
+ return;
+ }
+ g_object_add_weak_pointer (G_OBJECT (priv->presence_proxy), (gpointer *)&priv->presence_proxy);
+
+ if (tp_conn_iface_presence_get_statuses (priv->presence_proxy,
+ &status_hash, &error) == FALSE)
+ {
+ g_warning ("%s: Get statuses failed for account %s: %s", G_STRFUNC,
+ mc_account_get_unique_name (priv->account),
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* Everything went well so pack the available presences into
+ * connection info
+ */
+ /* Initialize presence info array and pointers for setting presences */
+ for (i = 0; i < LAST_MC_PRESENCE - 1; i++)
+ priv->presence_to_set[i] = NULL;
+ priv->recognized_presence_info_array =
+ g_array_new (FALSE, FALSE, sizeof (struct presence_info));
+ g_hash_table_foreach (status_hash, recognize_presence, priv);
+ g_hash_table_destroy (status_hash);
+
+ enable_well_known_presences (priv);
+
+ /* Set the fallback presence values */
+ for (i = 0; i < LAST_MC_PRESENCE - 1; i++)
+ {
+ if (priv->presence_to_set[i] == NULL)
+ _mcd_connection_set_fallback_presences (connection, i);
+ }
+ }
+
+ supported_presence_info = priv->presence_to_set[presence - 1];
+
+ if (supported_presence_info == NULL)
+ {
+ g_debug ("No matching supported presence found. "
+ "Account presence has not been changed.");
+ return;
+ }
+
+ presence_str = g_strdup (supported_presence_info->presence_str);
+ presence = presence_str_to_enum (supported_presence_info->presence_str);
+
+ /* Add the presence by libtelepathy */
+ /* FIXME: what should we do when this is NULL? */
+ if (presence_str != NULL)
+ {
+ presence_ht = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ params_ht = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /*
+ * Note that we silently ignore the message if Connection Manager
+ * doesn't support it for this presence state!
+ */
+ if (supported_presence_info->allow_message && presence_message)
+ {
+ g_value_init (&msg_gval, G_TYPE_STRING);
+ g_value_set_string (&msg_gval, presence_message);
+ g_hash_table_insert (params_ht, "message", &msg_gval);
+ }
+
+ g_hash_table_insert (presence_ht, (gpointer) presence_str, params_ht);
+
+ if (tp_conn_iface_presence_set_status (priv->presence_proxy,
+ presence_ht, &error) == FALSE)
+ {
+ g_warning ("%s: Setting presence of %s to %s (%d) failed: %s",
+ G_STRFUNC, mc_account_get_unique_name (priv->account),
+ presence_str, presence, error->message);
+ }
+ else
+ {
+ mcd_presence_frame_set_account_presence (priv->presence_frame,
+ priv->account,
+ presence,
+ presence_message);
+ }
+
+ if (supported_presence_info->allow_message && presence_message)
+ g_value_unset (&msg_gval);
+
+ g_hash_table_destroy (presence_ht);
+ g_hash_table_destroy (params_ht);
+ }
+}
+
+
+/* This handler should update the presence of the tp_connection.
+ * Note, that the only presence transition not served by this function
+ * is getting to non-offline state since when presence is offline this object
+ * does not exist.
+ *
+ * So, here we just submit the request to the tp_connection object. The return off
+ * the operation is handled by (yet to be written) handler
+ */
+static void
+on_presence_requested (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ const gchar * presence_message, gpointer user_data)
+{
+ McdConnection *connection = MCD_CONNECTION (user_data);
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ GError *error = NULL;
+
+ g_debug ("Presence requested: %d", presence);
+ if (presence == TP_CONN_PRESENCE_TYPE_OFFLINE ||
+ presence == TP_CONN_PRESENCE_TYPE_UNSET)
+ {
+ /* Connection Proxy */
+ priv->abort_reason = TP_CONN_STATUS_REASON_REQUESTED;
+ mcd_mission_disconnect (MCD_MISSION (connection));
+ if (priv->tp_conn)
+ tp_conn_disconnect (DBUS_G_PROXY (priv->tp_conn), &error);
+ }
+ else
+ {
+ _mcd_connection_set_presence (connection, presence, presence_message);
+ }
+}
+
+static void
+_mcd_connection_new_channel_cb (DBusGProxy * tp_conn_proxy,
+ const gchar * chan_obj_path,
+ const gchar * chan_type,
+ guint handle_type,
+ guint handle,
+ gboolean suppress_handler,
+ McdConnection * connection)
+{
+ TpChan *tp_chan;
+ McdChannel *channel;
+ McdConnectionPrivate *priv;
+
+ priv = MCD_CONNECTION_PRIV (connection);
+
+ /* ignore all our own requests (they have always suppress_handler = 1) as
+ * well as other requests for which our intervention has not been requested
+ * */
+ if (suppress_handler) return;
+
+ /* g_return_if_fail (TELEPATHY_IS_CHAN (tp_chan)); */
+ tp_chan = tp_chan_new (priv->dbus_connection, priv->bus_name,
+ chan_obj_path, chan_type, handle_type, handle);
+
+ /* It's an incoming channel, so we create a new McdChannel for it */
+ channel = mcd_channel_new (tp_chan,
+ chan_obj_path,
+ chan_type,
+ handle,
+ handle_type,
+ FALSE, /* incoming */
+ 0, 0); /* There is no requestor, obviously */
+
+ mcd_operation_take_mission (MCD_OPERATION (connection),
+ MCD_MISSION (channel));
+
+ /* Channel about to be dispatched */
+ mcd_channel_set_status (channel, MCD_CHANNEL_DISPATCHING);
+
+ /* Dispatch the incoming channel */
+ mcd_dispatcher_send (priv->dispatcher, channel);
+
+ g_object_unref (tp_chan);
+}
+
+static void
+_foreach_channel_remove (McdMission * mission, McdOperation * operation)
+{
+ g_assert (MCD_IS_MISSION (mission));
+ g_assert (MCD_IS_OPERATION (operation));
+
+ mcd_operation_remove_mission (operation, mission);
+}
+
+static void
+on_capabilities_changed (DBusGProxy *tp_conn_proxy,
+ GPtrArray *caps, McdChannel *channel)
+{
+ McdConnection *connection;
+ McdConnectionPrivate *priv;
+ gboolean found = FALSE;
+ GType type;
+ gchar *chan_type;
+ guint chan_handle, chan_handle_type;
+ DBusGProxyCall *call;
+ gint i;
+
+ connection = g_object_get_data (G_OBJECT (channel), "temporary_connection");
+ priv = MCD_CONNECTION_PRIV (connection);
+
+ g_debug ("%s: got capabilities for channel %p handle %d, type %s",
+ G_STRFUNC, channel, mcd_channel_get_handle (channel), mcd_channel_get_channel_type (channel));
+ type = dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_STRING,
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
+ G_TYPE_UINT, G_TYPE_INVALID);
+ for (i = 0; i < caps->len; i++)
+ {
+ GValue cap = { 0 };
+
+ g_value_init (&cap, type);
+ g_value_set_static_boxed (&cap, g_ptr_array_index(caps, i));
+ dbus_g_type_struct_get (&cap, 0, &chan_handle, 1, &chan_type, G_MAXUINT);
+ if (chan_handle == mcd_channel_get_handle (channel) &&
+ strcmp (chan_type, mcd_channel_get_channel_type (channel)) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ g_free (chan_type);
+ }
+
+ if (!found) return;
+ /* Return also if the "tp_chan_call" data is set (which means that a
+ * request for this channel has already been made) */
+ if (g_object_get_data (G_OBJECT (channel), "tp_chan_call") != NULL)
+ return;
+ chan_handle_type = mcd_channel_get_handle_type (channel);
+ g_debug ("%s: requesting channel again (type = %s, handle_type = %u, handle = %u)",
+ G_STRFUNC, chan_type, chan_handle_type, chan_handle);
+ call = tp_conn_request_channel_async(DBUS_G_PROXY(priv->tp_conn),
+ chan_type,
+ chan_handle_type,
+ chan_handle, TRUE,
+ mcd_async_request_chan_callback,
+ channel);
+ g_object_set_data (G_OBJECT (channel), "tp_chan_call", call);
+ g_free (chan_type);
+}
+
+static gboolean
+on_channel_capabilities_timeout (guint channel_handle, McdChannel *channel,
+ McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ struct capabilities_wait_data *cwd;
+ GError *mc_error;
+
+ cwd = g_object_get_data (G_OBJECT (channel), "error_on_creation");
+ if (!cwd) return FALSE;
+
+ /* We reach this point if this channel was waiting for capabilities; we
+ * abort it and return the original error */
+ g_debug ("%s: channel %p timed out, returning error!", G_STRFUNC, channel);
+
+ mc_error = map_tp_error_to_mc_error (channel, cwd->error);
+ g_signal_emit_by_name (G_OBJECT(priv->dispatcher), "dispatch-failed",
+ channel, mc_error);
+ g_error_free (mc_error);
+ g_object_set_data (G_OBJECT (channel), "error_on_creation", NULL);
+
+ /* No abort on channel, because we are the only one holding the only
+ * reference to this temporary channel.
+ */
+ return TRUE;
+}
+
+static gboolean
+on_capabilities_timeout (McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_debug ("%s: got_capabilities is %d", G_STRFUNC, priv->got_capabilities);
+ priv->got_capabilities = TRUE;
+ g_hash_table_foreach_remove (priv->pending_channels,
+ (GHRFunc)on_channel_capabilities_timeout,
+ connection);
+ priv->capabilities_timer = 0;
+ return FALSE;
+}
+
+static void
+_mcd_connection_setup_capabilities (McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ GPtrArray *capabilities;
+ GError *error = NULL;
+ const gchar *remove = NULL;
+
+ priv->capabilities_proxy = tp_conn_get_interface (priv->tp_conn,
+ TELEPATHY_CONN_IFACE_CAPABILITIES_QUARK);
+ if (!priv->capabilities_proxy)
+ {
+ g_debug ("%s: connection does not support capabilities interface", G_STRFUNC);
+ priv->got_capabilities = TRUE;
+ return;
+ }
+ g_object_add_weak_pointer (G_OBJECT (priv->capabilities_proxy), (gpointer *)&priv->capabilities_proxy);
+ capabilities = mcd_dispatcher_get_channel_capabilities (priv->dispatcher);
+ g_debug ("%s: advertising capabilities", G_STRFUNC);
+ tp_conn_iface_capabilities_advertise_capabilities (priv->capabilities_proxy,
+ capabilities,
+ &remove, NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("%s: AdvertiseCapabilities failed: %s", G_STRFUNC, error->message);
+ g_error_free(error);
+ }
+
+ if (priv->capabilities_timer)
+ {
+ g_warning ("This connection still has dangling capabilities timer on");
+ g_source_remove (priv->capabilities_timer);
+ }
+ priv->capabilities_timer =
+ g_timeout_add (1000 * 5, (GSourceFunc)on_capabilities_timeout, connection);
+}
+
+static void
+_mcd_connection_get_normalized_name (McdConnectionPrivate *priv)
+{
+ GArray *handles;
+ gchar **names = NULL;
+ GError *error = NULL;
+ guint self_handle;
+
+ tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn), &self_handle,
+ &error);
+ if (error)
+ {
+ g_warning ("%s: tp_conn_get_self_handle failed: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ return;
+ }
+
+ handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1);
+ g_array_append_val (handles, self_handle);
+ tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
+ TP_CONN_HANDLE_TYPE_CONTACT, handles,
+ &names, &error);
+ g_array_free (handles, TRUE);
+ if (error)
+ {
+ g_warning ("%s: tp_conn_inspect_handles failed: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ return;
+ }
+ if (names)
+ {
+ g_return_if_fail (names[0] != 0);
+ mc_account_set_normalized_name (priv->account, names[0]);
+ g_strfreev (names);
+ }
+}
+
+static void
+set_avatar_cb (DBusGProxy *proxy, char *token, GError *error, gpointer userdata)
+{
+ McdConnectionPrivate *priv = (McdConnectionPrivate *)userdata;
+ if (error)
+ {
+ g_warning ("%s: error: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ return;
+ }
+ g_debug ("%s: received token: %s", G_STRFUNC, token);
+ mc_account_set_avatar_token (priv->account, token);
+ g_free (token);
+}
+
+static void
+clear_avatar_cb (DBusGProxy *proxy, GError *error, gpointer userdata)
+{
+ gchar *filename = userdata;
+ if (!error)
+ {
+ g_debug ("%s: Clear avatar succeeded, removing %s", G_STRFUNC, filename);
+ g_remove (filename);
+ }
+ else
+ {
+ g_warning ("%s: error: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+ g_free (filename);
+}
+
+static void
+_mcd_connection_setup_avatar (McdConnectionPrivate *priv)
+{
+ gchar *filename, *mime_type, *token;
+ GArray *avatar;
+ GError *error = NULL;
+
+ priv->avatars_proxy = tp_conn_get_interface (priv->tp_conn,
+ TELEPATHY_CONN_IFACE_AVATARS_QUARK);
+ if (!priv->avatars_proxy)
+ {
+ g_debug ("%s: connection does not support avatar interface", G_STRFUNC);
+ return;
+ }
+ g_object_ref (priv->avatars_proxy);
+ if (!mc_account_get_avatar (priv->account, &filename, &mime_type, &token))
+ {
+ g_debug ("%s: mc_account_get_avatar() returned FALSE", G_STRFUNC);
+ return;
+ }
+
+ /* if the token is set, we have nothing to do */
+ if (!token && filename && g_file_test (filename, G_FILE_TEST_EXISTS))
+ {
+ avatar = g_array_new (FALSE, FALSE, 1);
+ g_return_if_fail (avatar != NULL);
+ if (g_file_get_contents (filename, &avatar->data, &avatar->len, &error))
+ {
+ if (avatar->len > 0)
+ tp_conn_iface_avatars_set_avatar_async (priv->avatars_proxy,
+ avatar, mime_type,
+ set_avatar_cb, priv);
+ else
+ tp_conn_iface_avatars_clear_avatar_async(priv->avatars_proxy,
+ clear_avatar_cb,
+ g_strdup (filename));
+
+ }
+ else
+ {
+ g_debug ("%s: error reading %s: %s", G_STRFUNC, filename, error->message);
+ g_error_free (error);
+ }
+ g_array_free (avatar, TRUE);
+ }
+
+ g_free (filename);
+ g_free (mime_type);
+ g_free (token);
+}
+
+static gboolean
+mcd_connection_reconnect (McdConnection *connection)
+{
+ g_debug ("%s: %p", G_STRFUNC, connection);
+ _mcd_connection_setup (connection);
+ return FALSE;
+}
+
+static void
+_mcd_connection_status_changed_cb (DBusGProxy * tp_conn_proxy,
+ TelepathyConnectionStatus conn_status,
+ TelepathyConnectionStatusReason
+ conn_reason, McdConnection * connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_debug ("%s: status_changed called from tp (%d)", G_STRFUNC, conn_status);
+
+ switch (conn_status)
+ {
+ case TP_CONN_STATUS_CONNECTING:
+ mcd_presence_frame_set_account_status (priv->presence_frame,
+ priv->account,
+ conn_status, conn_reason);
+ priv->abort_reason = TP_CONN_STATUS_REASON_NONE_SPECIFIED;
+ break;
+ case TP_CONN_STATUS_CONNECTED:
+ {
+ const gchar *presence_message;
+ McPresence requested_presence;
+
+ mcd_presence_frame_set_account_status (priv->presence_frame,
+ priv->account,
+ conn_status, conn_reason);
+ requested_presence =
+ mcd_presence_frame_get_requested_presence (priv->presence_frame);
+ presence_message =
+ mcd_presence_frame_get_requested_presence_message (priv->presence_frame);
+ _mcd_connection_set_presence (connection, requested_presence,
+ presence_message);
+ _mcd_connection_setup_capabilities (connection);
+ _mcd_connection_setup_avatar (priv);
+ _mcd_connection_get_normalized_name (priv);
+ priv->reconnect_interval = 30 * 1000; /* reset it to 30 seconds */
+ }
+ break;
+ case TP_CONN_STATUS_DISCONNECTED:
+ /* Connection could die during account status updated if its
+ * manager is the only one holding the reference to it (manager will
+ * remove the connection from itself). To ensure we get a chance to
+ * emit abort signal (there could be others holding a ref to it), we
+ * will hold a temporary ref to it.
+ */
+ priv->abort_reason = conn_reason;
+
+ /* Destroy any pending timer */
+ if (priv->capabilities_timer)
+ g_source_remove (priv->capabilities_timer);
+ priv->capabilities_timer = 0;
+
+ /* Notify connection abort */
+ if (conn_reason == TP_CONN_STATUS_REASON_NETWORK_ERROR ||
+ conn_reason == TP_CONN_STATUS_REASON_NONE_SPECIFIED)
+ {
+ /* we were disconnected by a network error or by a gabble crash (in
+ * the latter case, we get NoneSpecified as a reason): don't abort
+ * the connection but try to reconnect later */
+ _mcd_connection_release_tp_connection (connection);
+ priv->reconnect_timer = g_timeout_add (priv->reconnect_interval,
+ (GSourceFunc)mcd_connection_reconnect,
+ connection);
+ priv->reconnect_interval *= 2;
+ if (priv->reconnect_interval >= 30 * 60 * 1000)
+ /* no more than 30 minutes! */
+ priv->reconnect_interval = 30 * 60 * 1000;
+ /* FIXME HACK: since we want presence-applet to immediately start
+ * displaying a blinking icon, we must set the account status to
+ * CONNECTING now */
+ mcd_presence_frame_set_account_status (priv->presence_frame,
+ priv->account,
+ TP_CONN_STATUS_CONNECTING,
+ TP_CONN_STATUS_REASON_REQUESTED);
+ return;
+ }
+
+ g_object_ref (connection);
+ /* Notify connection abort */
+ mcd_mission_abort (MCD_MISSION (connection));
+ g_object_unref (connection);
+ break;
+ default:
+ g_warning ("Unknown telepathy connection status");
+ }
+}
+
+static gint
+disconnect_on_error_idle (McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ /* Just synthesize the missing signal. */
+ _mcd_connection_status_changed_cb (DBUS_G_PROXY (priv->tp_conn),
+ TP_CONN_STATUS_DISCONNECTED,
+ TP_CONN_STATUS_REASON_NONE_SPECIFIED,
+ connection);
+ return FALSE;
+}
+
+static void proxy_destroyed (DBusGProxy *tp_conn, McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ g_debug ("Proxy destroyed!");
+ priv->tp_conn = NULL;
+ _mcd_connection_status_changed_cb (tp_conn,
+ TP_CONN_STATUS_DISCONNECTED,
+ TP_CONN_STATUS_REASON_NONE_SPECIFIED,
+ connection);
+ g_object_unref (tp_conn);
+}
+
+static void
+_mcd_connection_setup (McdConnection * connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_return_if_fail (priv->bus_name);
+ g_return_if_fail (priv->tp_conn_mgr);
+ g_return_if_fail (priv->account);
+
+ if (priv->reconnect_timer)
+ {
+ g_source_remove (priv->reconnect_timer);
+ priv->reconnect_timer = 0;
+ }
+
+ /* FIXME HACK: the correct test is
+
+ if (mcd_connection_get_connection_status (connection) ==
+ TP_CONN_STATUS_DISCONNECTED)
+ * but since we set the account status to CONNECTING as soon as we got
+ * disconnected by a network error, we must accept that status, too */
+ if (mcd_connection_get_connection_status (connection) !=
+ TP_CONN_STATUS_CONNECTED)
+ {
+ TelepathyConnectionStatus conn_status;
+
+ /* FIXME: Can we do it easier? */
+ GHashTable *params;
+ McProfile *profile;
+ const gchar *protocol_name;
+ const gchar *account_name;
+
+ profile = mc_account_get_profile (priv->account);
+ protocol_name = mc_profile_get_protocol_name (profile);
+ account_name = mc_account_get_unique_name (priv->account);
+
+ g_debug ("%s: Trying connect account: %s",
+ G_STRFUNC, (gchar *) account_name);
+
+ params = mc_account_get_params (priv->account);
+
+ /* FIXME: Libtelepathy has non-const on the name. Why's that? */
+ priv->tp_conn = tp_connmgr_new_connection (priv->tp_conn_mgr,
+ params,
+ (gchar *) protocol_name);
+ g_hash_table_destroy (params);
+ g_object_unref (profile);
+
+ mcd_presence_frame_set_account_status (priv->presence_frame,
+ priv->account,
+ TP_CONN_STATUS_CONNECTING,
+ TP_CONN_STATUS_REASON_REQUESTED);
+ if (!priv->tp_conn)
+ {
+ g_warning ("%s: tp_connmgr_new_connection returned NULL", G_STRFUNC);
+ mcd_presence_frame_set_account_status (priv->presence_frame,
+ priv->account,
+ TP_CONN_STATUS_DISCONNECTED,
+ TP_CONN_STATUS_REASON_NETWORK_ERROR);
+ return;
+ }
+
+ /* Setup signals */
+ g_signal_connect (priv->tp_conn, "destroy",
+ G_CALLBACK (proxy_destroyed), connection);
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
+ G_CALLBACK
+ (_mcd_connection_new_channel_cb),
+ connection, NULL);
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn),
+ "StatusChanged",
+ G_CALLBACK
+ (_mcd_connection_status_changed_cb),
+ connection, NULL);
+
+ /* We might have lost a StatusChanged signal before we connect to
+ * it because DISCONNECTION happened so fast.
+ */
+ tp_conn_get_status (DBUS_G_PROXY (priv->tp_conn), &conn_status, NULL);
+ if (conn_status == TP_CONN_STATUS_DISCONNECTED)
+ {
+ g_debug ("Connection is in DISCONNECTED state!");
+ g_idle_add ((GSourceFunc)disconnect_on_error_idle, connection);
+ }
+ }
+ else
+ {
+ g_debug ("%s: Not connecting because not disconnected (%i)",
+ G_STRFUNC, mcd_connection_get_connection_status (connection));
+ return;
+ }
+}
+
+static void
+_mcd_connection_finalize (GObject * object)
+{
+ McdConnection *connection = MCD_CONNECTION (object);
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_free (priv->bus_name);
+
+ _mcd_connection_free_presence_info (connection);
+
+ G_OBJECT_CLASS (mcd_connection_parent_class)->finalize (object);
+}
+
+static void
+_mcd_connection_release_tp_connection (McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_debug ("%s(%p) called", G_STRFUNC, connection);
+ mcd_presence_frame_set_account_status (priv->presence_frame,
+ priv->account,
+ TP_CONN_STATUS_DISCONNECTED,
+ priv->abort_reason);
+ if (priv->tp_conn)
+ {
+ /* Disconnect signals */
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn),
+ "StatusChanged",
+ G_CALLBACK
+ (_mcd_connection_status_changed_cb),
+ connection);
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn),
+ "NewChannel",
+ G_CALLBACK
+ (_mcd_connection_new_channel_cb),
+ connection);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (priv->tp_conn),
+ G_CALLBACK (proxy_destroyed),
+ connection);
+
+
+ tp_conn_disconnect (DBUS_G_PROXY (priv->tp_conn), NULL);
+ g_object_unref (priv->tp_conn);
+ priv->tp_conn = NULL;
+ }
+
+ /* the interface proxies obtained from this connection must be deleted, too
+ */
+ if (priv->presence_proxy)
+ {
+ g_object_remove_weak_pointer (G_OBJECT(priv->presence_proxy),
+ (gpointer *)&priv->presence_proxy);
+ priv->presence_proxy = NULL;
+ }
+ if (priv->capabilities_proxy)
+ {
+ g_object_remove_weak_pointer (G_OBJECT(priv->capabilities_proxy),
+ (gpointer *)&priv->capabilities_proxy);
+ priv->capabilities_proxy = NULL;
+ }
+ if (priv->avatars_proxy)
+ {
+ g_object_unref (priv->avatars_proxy);
+ priv->avatars_proxy = NULL;
+ }
+ _mcd_connection_free_presence_info (connection);
+}
+
+static void
+_mcd_connection_dispose (GObject * object)
+{
+ McdConnection *connection = MCD_CONNECTION (object);
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_debug ("%s called for object %p", G_STRFUNC, object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+
+ priv->is_disposed = TRUE;
+
+ /* Remove any pending source: timer and idle */
+ g_source_remove_by_user_data (connection);
+ priv->capabilities_timer = 0;
+
+ mcd_operation_foreach (MCD_OPERATION (connection),
+ (GFunc) _foreach_channel_remove, connection);
+
+ /* Unref pending channels */
+ g_hash_table_destroy (priv->pending_channels);
+
+ _mcd_connection_release_tp_connection (connection);
+
+ if (priv->presence_frame != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT
+ (priv->presence_frame),
+ G_CALLBACK
+ (on_presence_requested), object);
+ g_object_unref (priv->presence_frame);
+ priv->presence_frame = NULL;
+ }
+
+ if (priv->account)
+ {
+ g_object_unref (priv->account);
+ priv->account = NULL;
+ }
+
+ if (priv->tp_conn_mgr)
+ {
+ g_object_unref (priv->tp_conn_mgr);
+ priv->tp_conn_mgr = NULL;
+ }
+
+ if (priv->dispatcher)
+ {
+ g_object_unref (priv->dispatcher);
+ priv->dispatcher = NULL;
+ }
+
+ G_OBJECT_CLASS (mcd_connection_parent_class)->dispose (object);
+}
+
+static void
+_mcd_connection_set_property (GObject * obj, guint prop_id,
+ const GValue * val, GParamSpec * pspec)
+{
+ McdPresenceFrame *presence_frame;
+ McdDispatcher *dispatcher;
+ DBusGConnection *dbus_connection;
+ McAccount *account;
+ TpConnMgr *tp_conn_mgr;
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_PRESENCE_FRAME:
+ presence_frame = g_value_get_object (val);
+ if (presence_frame)
+ {
+ g_return_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame));
+ g_object_ref (presence_frame);
+ }
+
+ if (priv->presence_frame)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT
+ (priv->presence_frame),
+ G_CALLBACK
+ (on_presence_requested), obj);
+ g_object_unref (priv->presence_frame);
+ }
+ priv->presence_frame = presence_frame;
+ if (priv->presence_frame)
+ {
+ g_signal_connect_after (G_OBJECT (priv->presence_frame),
+ "presence-requested",
+ G_CALLBACK (on_presence_requested), obj);
+ }
+ break;
+ case PROP_DISPATCHER:
+ dispatcher = g_value_get_object (val);
+ if (dispatcher)
+ {
+ g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
+ g_object_ref (dispatcher);
+ }
+ if (priv->dispatcher)
+ {
+ g_object_unref (priv->dispatcher);
+ }
+ priv->dispatcher = dispatcher;
+ break;
+ case PROP_DBUS_CONNECTION:
+ dbus_connection = g_value_get_pointer (val);
+ dbus_g_connection_ref (dbus_connection);
+ if (priv->dbus_connection)
+ dbus_g_connection_unref (priv->dbus_connection);
+ priv->dbus_connection = dbus_connection;
+ break;
+ case PROP_BUS_NAME:
+ g_return_if_fail (g_value_get_string (val) != NULL);
+ g_free (priv->bus_name);
+ priv->bus_name = g_strdup (g_value_get_string (val));
+ break;
+ case PROP_TP_MANAGER:
+ tp_conn_mgr = g_value_get_object (val);
+ g_return_if_fail (TELEPATHY_IS_CONNMGR (tp_conn_mgr));
+ g_object_ref (tp_conn_mgr);
+ if (priv->tp_conn_mgr)
+ g_object_unref (priv->tp_conn_mgr);
+ priv->tp_conn_mgr = tp_conn_mgr;
+ break;
+ case PROP_ACCOUNT:
+ account = g_value_get_object (val);
+ g_return_if_fail (MC_IS_ACCOUNT (account));
+ g_object_ref (account);
+ if (priv->account)
+ g_object_unref (priv->account);
+ priv->account = account;
+ _mcd_connection_setup (MCD_CONNECTION (obj));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_connection_get_property (GObject * obj, guint prop_id,
+ GValue * val, GParamSpec * pspec)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_DBUS_CONNECTION:
+ g_value_set_pointer (val, priv->dbus_connection);
+ break;
+ case PROP_BUS_NAME:
+ g_value_set_string (val, priv->bus_name);
+ break;
+ case PROP_ACCOUNT:
+ g_value_set_object (val, priv->account);
+ break;
+ case PROP_TP_MANAGER:
+ g_value_set_object (val, priv->tp_conn_mgr);
+ break;
+ case PROP_TP_CONNECTION:
+ g_value_set_object (val, priv->tp_conn);
+ break;
+ case PROP_PRESENCE_FRAME:
+ g_value_set_object (val, priv->presence_frame);
+ break;
+ case PROP_DISPATCHER:
+ g_value_set_object (val, priv->dispatcher);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mcd_connection_class_init (McdConnectionClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McdConnectionPrivate));
+
+ object_class->finalize = _mcd_connection_finalize;
+ object_class->dispose = _mcd_connection_dispose;
+ object_class->set_property = _mcd_connection_set_property;
+ object_class->get_property = _mcd_connection_get_property;
+
+ /* Properties */
+ g_object_class_install_property (object_class,
+ PROP_PRESENCE_FRAME,
+ g_param_spec_object ("presence-frame",
+ _
+ ("Presence Frame Object"),
+ _
+ ("Presence frame Object used by connections to update presence"),
+ MCD_TYPE_PRESENCE_FRAME,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPATCHER,
+ g_param_spec_object ("dispatcher",
+ _("Dispatcher Object"),
+ _("Dispatcher to dispatch channels"),
+ MCD_TYPE_DISPATCHER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_DBUS_CONNECTION,
+ g_param_spec_pointer ("dbus-connection",
+ _("DBus Connection"),
+ _
+ ("DBus connection to use by us"),
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_BUS_NAME,
+ g_param_spec_string ("bus-name",
+ _("DBus Bus name"),
+ _
+ ("DBus Bus name to use by us"),
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_TP_MANAGER,
+ g_param_spec_object ("tp-manager",
+ _
+ ("Telepathy Manager Object"),
+ _
+ ("Telepathy Manager Object which this connection uses"),
+ TELEPATHY_CONNMGR_TYPE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_TP_CONNECTION,
+ g_param_spec_object ("tp-connection",
+ _
+ ("Telepathy Connection Object"),
+ _
+ ("Telepathy Connection Object which this connection uses"),
+ TELEPATHY_CONN_TYPE,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class, PROP_ACCOUNT,
+ g_param_spec_object ("account",
+ _("Account Object"),
+ _
+ ("Account that will be used to create this connection"),
+ MC_TYPE_ACCOUNT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+release_channel_object (gpointer object)
+{
+ g_object_unref (object);
+}
+
+static void
+mcd_connection_init (McdConnection * connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ priv->pending_channels = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ release_channel_object);
+ priv->abort_reason = TP_CONN_STATUS_REASON_NONE_SPECIFIED;
+
+ priv->reconnect_interval = 30 * 1000; /* 30 seconds */
+}
+
+/* Public methods */
+
+/* Creates a new connection object. Increases a refcount of account.
+ * Uses mcd_get_manager function to get TpConnManager
+ */
+McdConnection *
+mcd_connection_new (DBusGConnection * dbus_connection,
+ const gchar * bus_name,
+ TpConnMgr * tp_conn_mgr,
+ McAccount * account,
+ McdPresenceFrame * presence_frame,
+ McdDispatcher *dispatcher)
+{
+ McdConnection *mcdconn = NULL;
+ g_return_val_if_fail (dbus_connection != NULL, NULL);
+ g_return_val_if_fail (bus_name != NULL, NULL);
+ g_return_val_if_fail (TELEPATHY_IS_CONNMGR (tp_conn_mgr), NULL);
+ g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame), NULL);
+
+ mcdconn = g_object_new (MCD_TYPE_CONNECTION,
+ "dbus-connection", dbus_connection,
+ "bus-name", bus_name,
+ "tp-manager", tp_conn_mgr,
+ "presence-frame", presence_frame,
+ "dispatcher", dispatcher,
+ "account", account, NULL);
+ return mcdconn;
+}
+
+/* Constant getters. These should probably be removed */
+
+const McAccount *
+mcd_connection_get_account (McdConnection * id)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (id);
+ return priv->account;
+}
+
+TelepathyConnectionStatus
+mcd_connection_get_connection_status (McdConnection * id)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (id);
+ return mcd_presence_frame_get_account_status (priv->presence_frame,
+ priv->account);
+}
+
+gboolean
+mcd_connection_get_telepathy_details (McdConnection * id,
+ gchar ** ret_servname,
+ gchar ** ret_objpath)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (id);
+
+ g_return_val_if_fail (priv->tp_conn != NULL, FALSE);
+ g_return_val_if_fail (TELEPATHY_IS_CONN (priv->tp_conn), FALSE);
+
+ /* Query the properties required for creation of identical TpConn object */
+ *ret_objpath =
+ g_strdup (dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_conn)));
+ *ret_servname =
+ g_strdup (dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn)));
+
+ return TRUE;
+}
+
+static GError *
+map_tp_error_to_mc_error (McdChannel *channel, GError *tp_error)
+{
+ MCError mc_error_code = MC_CHANNEL_REQUEST_GENERIC_ERROR;
+
+ g_warning ("Telepathy Error = %s", tp_error->message);
+
+ /* TODO : Are there still more specific errors we need
+ * to distinguish?
+ */
+ if (mcd_channel_get_channel_type_quark (channel) ==
+ TELEPATHY_CHAN_IFACE_STREAMED_QUARK &&
+ dbus_g_error_has_name(tp_error, "org.freedesktop.Telepathy.Error.NotAvailable"))
+ {
+ mc_error_code = MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR;
+ }
+ else if (dbus_g_error_has_name(tp_error, "org.freedesktop.Telepathy.Error.ChannelBanned"))
+ {
+ mc_error_code = MC_CHANNEL_BANNED_ERROR;
+ }
+ else if (dbus_g_error_has_name(tp_error, "org.freedesktop.Telepathy.Error.ChannelFull"))
+ {
+ mc_error_code = MC_CHANNEL_FULL_ERROR;
+ }
+ else if (dbus_g_error_has_name(tp_error, "org.freedesktop.Telepathy.Error.ChannelInviteOnly"))
+ {
+ mc_error_code = MC_CHANNEL_INVITE_ONLY_ERROR;
+ }
+ return g_error_new (MC_ERROR, mc_error_code, "Telepathy Error: %s",
+ tp_error->message);
+}
+
+static void
+remove_capabilities_refs (gpointer data)
+{
+ struct capabilities_wait_data *cwd = data;
+
+ g_debug ("\n\n\n%s called\n\n\n", G_STRFUNC);
+ dbus_g_proxy_disconnect_signal (cwd->priv->capabilities_proxy,
+ "CapabilitiesChanged",
+ G_CALLBACK (on_capabilities_changed),
+ cwd->channel);
+ g_error_free (cwd->error);
+ g_free (cwd);
+}
+
+static void
+mcd_async_request_chan_callback (DBusGProxy *proxy,
+ gchar *channel_path,
+ GError *error,
+ gpointer user_data)
+{
+ McdChannel *channel;
+ McdConnection *connection;
+ McdConnectionPrivate *priv;
+ GError *error_on_creation;
+ struct capabilities_wait_data *cwd;
+ gchar *chan_type;
+ TelepathyHandleType chan_handle_type;
+ guint chan_handle;
+ TpChan *tp_chan;
+ /* We handle only the dbus errors */
+
+ /* ChannelRequestor *chan_req = (ChannelRequestor *)user_data; */
+ channel = MCD_CHANNEL (user_data); /* the not-yet-added channel */
+ connection = g_object_get_data (G_OBJECT (channel), "temporary_connection");
+ g_object_steal_data (G_OBJECT (channel), "tp_chan_call");
+ priv = MCD_CONNECTION_PRIV (connection);
+
+ g_object_get (channel,
+ "channel-handle", &chan_handle,
+ "channel-handle-type", &chan_handle_type,
+ NULL);
+
+
+ cwd = g_object_get_data (G_OBJECT (channel), "error_on_creation");
+ if (cwd)
+ {
+ error_on_creation = cwd->error;
+ g_object_set_data (G_OBJECT (channel), "error_on_creation", NULL);
+ }
+ else
+ error_on_creation = NULL;
+
+
+ if (error != NULL)
+ {
+ g_debug ("%s: Got error: %s", G_STRFUNC, error->message);
+ if (error_on_creation != NULL)
+ {
+ /* replace the error, so that the initial one is reported */
+ g_error_free (error);
+ error = error_on_creation;
+ }
+
+ if (priv->got_capabilities || error_on_creation)
+ {
+ /* Faild dispatch */
+ GError *mc_error = map_tp_error_to_mc_error (channel, error);
+ g_signal_emit_by_name (G_OBJECT(priv->dispatcher), "dispatch-failed",
+ channel, mc_error);
+ g_error_free (mc_error);
+ g_error_free (error);
+
+ /* No abort on channel, because we are the only one holding the only
+ * reference to this temporary channel.
+ * This should also unref the channel object
+ */
+ g_hash_table_remove (priv->pending_channels,
+ GINT_TO_POINTER (chan_handle));
+ }
+ else
+ {
+ /* the channel request has failed probably because we are just
+ * connected and we didn't recive the contact capabilities yet. In
+ * this case, wait for this contact's capabilities to arrive */
+ g_debug ("%s: listening for remote capabilities on channel handle %d, type %d",
+ G_STRFUNC, chan_handle, mcd_channel_get_handle_type (channel));
+ dbus_g_proxy_connect_signal (priv->capabilities_proxy,
+ "CapabilitiesChanged",
+ G_CALLBACK (on_capabilities_changed),
+ channel, NULL);
+ /* Store the error, we might need it later */
+ cwd = g_malloc (sizeof (struct capabilities_wait_data));
+ g_assert (cwd != NULL);
+ cwd->error = error;
+ cwd->channel = channel;
+ cwd->priv = priv;
+ g_object_set_data_full (G_OBJECT (channel), "error_on_creation", cwd,
+ remove_capabilities_refs);
+ }
+ return;
+ }
+
+ if (channel_path == NULL)
+ {
+ GError *mc_error;
+ g_warning ("Returned channel_path from telepathy is NULL");
+
+ mc_error = g_error_new (MC_ERROR,
+ MC_CHANNEL_REQUEST_GENERIC_ERROR,
+ "Returned channel_path from telepathy is NULL");
+ g_signal_emit_by_name (G_OBJECT(priv->dispatcher),
+ "dispatch-failed", channel, mc_error);
+ g_error_free (mc_error);
+
+ /* No abort on channel, because we are the only one holding the only
+ * reference to this temporary channel.
+ * This should also unref the channel object
+ */
+ g_hash_table_remove (priv->pending_channels,
+ GINT_TO_POINTER (chan_handle));
+ return;
+ }
+
+ /* Everything here is well and fine. We can create the channel. */
+ channel = g_hash_table_lookup (priv->pending_channels,
+ GUINT_TO_POINTER (chan_handle));
+ if (!channel)
+ {
+ g_warning ("%s: channel not found among the pending ones", G_STRFUNC);
+ return;
+ }
+
+ g_object_get (channel,
+ "channel-type", &chan_type,
+ NULL);
+ tp_chan = tp_chan_new (priv->dbus_connection, priv->bus_name,
+ channel_path, chan_type, chan_handle_type, chan_handle);
+ g_object_set (channel,
+ "channel-object-path", channel_path,
+ "tp-channel", tp_chan,
+ NULL);
+
+ /* The channel is no longer pending. 'stealing' because want the
+ * channel ownership.
+ */
+ g_hash_table_steal (priv->pending_channels,
+ GINT_TO_POINTER (chan_handle));
+ mcd_operation_take_mission (MCD_OPERATION (connection),
+ MCD_MISSION (channel));
+
+ /* Channel about to be dispatched */
+ mcd_channel_set_status (channel, MCD_CHANNEL_DISPATCHING);
+
+ /* Dispatch the incoming channel */
+ mcd_dispatcher_send (priv->dispatcher, channel);
+
+ g_free (chan_type);
+ g_free (channel_path);
+ g_object_unref (tp_chan);
+}
+
+static void
+mcd_async_request_handle_callback(DBusGProxy *proxy, GArray *handles,
+ GError *error, gpointer user_data)
+{
+ McdChannel *channel, *existing_channel;
+ McdConnection *connection;
+ McdConnectionPrivate *priv;
+ guint chan_handle, chan_handle_type;
+ const gchar *chan_type;
+ const GList *channels;
+ DBusGProxyCall *call;
+
+ channel = MCD_CHANNEL (user_data);
+ connection = g_object_get_data (G_OBJECT (channel), "temporary_connection");
+ priv = MCD_CONNECTION_PRIV (connection);
+
+ if (error != NULL)
+ {
+ GError *mc_error;
+ g_warning ("Could not map string handle to a valid handle!: %s",
+ error->message);
+
+ /* Fail dispatch */
+ mc_error = g_error_new (MC_ERROR, MC_INVALID_HANDLE_ERROR,
+ "Could not map string handle to a valid handle!: %s",
+ error->message);
+ g_signal_emit_by_name (priv->dispatcher, "dispatch-failed",
+ channel, mc_error);
+ g_error_free (mc_error);
+ g_error_free(error);
+
+ /* No abort, because we are the only one holding the only reference
+ * to this temporary channel
+ */
+ g_object_unref (channel);
+ return;
+ }
+
+ chan_type = mcd_channel_get_channel_type (channel),
+ chan_handle_type = mcd_channel_get_handle_type (channel),
+ chan_handle = g_array_index (handles, guint, 0);
+ g_array_free(handles, TRUE);
+
+ g_debug ("Got handle %u", chan_handle);
+
+ /* Is the handle we got valid? */
+ if (chan_handle == 0)
+ {
+ GError *mc_error;
+ g_warning ("Could not map the string to a valid handle!");
+
+ /* Fail dispatch */
+ mc_error = g_error_new (MC_ERROR, MC_INVALID_HANDLE_ERROR,
+ "Could not map string handle to a valid handle!");
+ g_signal_emit_by_name (priv->dispatcher, "dispatch-failed",
+ channel, mc_error);
+ g_error_free (mc_error);
+
+ /* No abort, because we are the only one holding the only reference
+ * to this temporary channel
+ */
+ g_object_unref (channel);
+ return;
+ }
+
+ /* Check if a telepathy channel has already been created; this could happen
+ * in the case we had a chat window open, the UI crashed and now the same
+ * channel is requested. */
+ channels = mcd_operation_get_missions (MCD_OPERATION (connection));
+ while (channels)
+ {
+ existing_channel = MCD_CHANNEL (channels->data);
+ g_debug ("Chan: %d, handle type %d, channel type %s",
+ mcd_channel_get_handle (existing_channel),
+ mcd_channel_get_handle_type (existing_channel),
+ mcd_channel_get_channel_type (existing_channel));
+ if (chan_handle == mcd_channel_get_handle (existing_channel) &&
+ strcmp(chan_type,
+ mcd_channel_get_channel_type (existing_channel)) == 0)
+ {
+ guint requestor_serial;
+ gchar *requestor_client_id;
+
+ g_debug ("%s: Channel already existing, returning old one", G_STRFUNC);
+ /* we retrieve the information we need from the newly created
+ * channel object and set them to the "old" channel */
+ g_object_get (channel,
+ "requestor-serial", &requestor_serial,
+ "requestor-client-id", &requestor_client_id,
+ NULL);
+ g_object_set (existing_channel,
+ "requestor-serial", requestor_serial,
+ "requestor-client-id", requestor_client_id,
+ NULL);
+ g_free (requestor_client_id);
+ /* we no longer need the new channel */
+ g_object_unref (channel);
+ /* notify the dispatcher again */
+ mcd_dispatcher_send (priv->dispatcher, existing_channel);
+ return;
+ }
+ channels = channels->next;
+ }
+
+ /* Update our newly acquired information */
+ g_object_set (channel, "channel-handle", chan_handle, NULL);
+
+ /* The channel is temporary and stays in priv->pending_channels until
+ * a telepathy channel for it is created
+ */
+ g_hash_table_insert (priv->pending_channels,
+ GINT_TO_POINTER (chan_handle), channel);
+
+ /* Now, request the corresponding telepathy channel. */
+ call = tp_conn_request_channel_async(DBUS_G_PROXY(proxy),
+ mcd_channel_get_channel_type (channel),
+ mcd_channel_get_handle_type (channel),
+ chan_handle, TRUE,
+ mcd_async_request_chan_callback,
+ channel);
+ g_object_set_data (G_OBJECT (channel), "tp_chan_call", call);
+}
+
+gboolean
+mcd_connection_request_channel (McdConnection *connection,
+ const struct mcd_channel_request *req,
+ GError ** error)
+{
+ McdChannel *channel;
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ g_return_val_if_fail (priv->tp_conn != NULL, FALSE);
+ g_return_val_if_fail (TELEPATHY_IS_CONN (priv->tp_conn), FALSE);
+
+ /* The channel is temporary */
+ channel = mcd_channel_new (NULL,
+ NULL,
+ req->channel_type,
+ req->channel_handle,
+ req->channel_handle_type,
+ TRUE, /* outgoing */
+ req->requestor_serial,
+ req->requestor_client_id);
+
+ /* We do not add the channel in connection until tp_channel is created */
+ g_object_set_data (G_OBJECT (channel), "temporary_connection", connection);
+
+ if (req->channel_handle)
+ {
+ DBusGProxyCall *call;
+ /* the channel stays in priv->pending_channels until a telepathy
+ * channel for it is created */
+ g_hash_table_insert (priv->pending_channels,
+ GINT_TO_POINTER (req->channel_handle), channel);
+
+ call = tp_conn_request_channel_async(DBUS_G_PROXY(priv->tp_conn),
+ req->channel_type,
+ req->channel_handle_type,
+ req->channel_handle, TRUE,
+ mcd_async_request_chan_callback,
+ channel);
+ g_object_set_data (G_OBJECT (channel), "tp_chan_call", call);
+ }
+ else
+ {
+ /* if channel handle is 0, this means that the channel was requested by
+ * a string handle; in that case, we must first request a channel
+ * handle for it */
+ const gchar *name_array[2];
+ g_assert (req->channel_handle_string != NULL);
+
+ name_array[0] = req->channel_handle_string;
+ name_array[1] = NULL;
+
+ /* Channel is temporary and will enter priv->pending_channels list
+ * only when we successfully resolve the handle. */
+ tp_conn_request_handles_async (DBUS_G_PROXY(priv->tp_conn),
+ req->channel_handle_type,
+ name_array,
+ mcd_async_request_handle_callback,
+ channel);
+ }
+ return TRUE;
+}
+
+static gboolean
+channel_matches_request (gpointer key, McdChannel *channel,
+ struct request_id *req_id)
+{
+ guint requestor_serial;
+ gchar *requestor_client_id;
+ gboolean found;
+
+ g_object_get (channel,
+ "requestor-serial", &requestor_serial,
+ "requestor-client-id", &requestor_client_id,
+ NULL);
+ if (requestor_serial == req_id->requestor_serial &&
+ strcmp (requestor_client_id, req_id->requestor_client_id) == 0)
+ found = TRUE;
+ else
+ found = FALSE;
+ g_free (requestor_client_id);
+ return found;
+}
+
+gboolean
+mcd_connection_cancel_channel_request (McdConnection *connection,
+ guint operation_id,
+ const gchar *requestor_client_id,
+ GError **error)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ struct request_id req_id;
+ const GList *channels, *node;
+ McdChannel *channel;
+
+ /* first, see if the channel is in the list of the pending channels */
+ req_id.requestor_serial = operation_id;
+ req_id.requestor_client_id = requestor_client_id;
+ channel = g_hash_table_find (priv->pending_channels,
+ (GHRFunc)channel_matches_request,
+ &req_id);
+ if (channel)
+ {
+ guint chan_handle;
+ DBusGProxyCall *call;
+
+ g_debug ("%s: requested channel found in the pending_channels list (%p)", G_STRFUNC, channel);
+ g_object_get (channel,
+ "channel-handle", &chan_handle,
+ NULL);
+ /* check for pending dbus calls to be cancelled */
+ call = g_object_get_data (G_OBJECT (channel), "tp_chan_call");
+ dbus_g_proxy_cancel_call (DBUS_G_PROXY(priv->tp_conn), call);
+ /* No abort on channel, because we are the only one holding the only
+ * reference to this temporary channel.
+ * This should also unref the channel object.
+ * No other actions needed; if a NewChannel signal will be emitted for
+ * this channel, it will be ignored since it has the suppress_handler
+ * flag set.
+ */
+ g_hash_table_remove (priv->pending_channels,
+ GINT_TO_POINTER (chan_handle));
+ return TRUE;
+ }
+
+ /* the channel might already have a TpChan created for it, and either be in
+ * the dispatcher or be already handled. Aborting in any case. */
+ channels = mcd_operation_get_missions (MCD_OPERATION (connection));
+ if (!channels) return FALSE;
+
+ for (node = channels; node; node = node->next)
+ {
+ guint chan_requestor_serial;
+ gchar *chan_requestor_client_id;
+
+ channel = MCD_CHANNEL (node->data);
+ g_object_get (channel,
+ "requestor-serial", &chan_requestor_serial,
+ "requestor-client-id", &chan_requestor_client_id,
+ NULL);
+ if (chan_requestor_serial == operation_id &&
+ strcmp (chan_requestor_client_id, requestor_client_id) == 0)
+ {
+ g_debug ("%s: requested channel found (%p)", G_STRFUNC, channel);
+ mcd_mission_abort (MCD_MISSION (channel));
+ g_free (chan_requestor_client_id);
+ return TRUE;
+ }
+ g_free (chan_requestor_client_id);
+ }
+ g_debug ("%s: requested channel not found!", G_STRFUNC);
+ return FALSE;
+}
+
+static void
+request_avatar_cb (DBusGProxy *proxy, GArray *avatar, char *mime_type,
+ GError *error, gpointer userdata)
+{
+ McdConnectionPrivate *priv = (McdConnectionPrivate *)userdata;
+ gchar *filename;
+ if (error)
+ {
+ g_warning ("%s: error: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ return;
+ }
+ g_debug ("%s: received mime-type: %s", G_STRFUNC, mime_type);
+ if (mc_account_get_avatar (priv->account, &filename, NULL, NULL))
+ {
+ g_file_set_contents (filename, avatar->data, avatar->len, NULL);
+ mc_account_set_avatar_mime_type (priv->account, mime_type);
+ mc_account_reset_avatar_id (priv->account);
+ g_free (filename);
+ }
+ g_free (mime_type);
+}
+
+/** mcd_connection_remote_avatar_changed:
+ * @connection: the #McdConnection.
+ * @contact_id: the own contact id in Telepathy.
+ * @token: the new avatar token.
+ *
+ * This function is to be called when Telepathy signals that our own avatar has
+ * been updated. It takes care of checking if the remote avatar has to be
+ * retrieved and stored in the account.
+ *
+ * Returns: %TRUE if the local avatar has been updated.
+ */
+gboolean mcd_connection_remote_avatar_changed (McdConnection *connection,
+ guint contact_id,
+ const gchar *token)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+ gchar *prev_token;
+ gboolean changed = FALSE;
+
+ if (!priv->avatars_proxy)
+ {
+ g_warning ("%s: avatar proxy is gone", G_STRFUNC);
+ return FALSE;
+ }
+
+ if (!mc_account_get_avatar (priv->account, NULL, NULL, &prev_token))
+ return FALSE;
+
+ if (!prev_token || strcmp (token, prev_token) != 0)
+ {
+ g_debug ("%s: avatar has changed", G_STRFUNC);
+ /* the avatar has changed, let's retrieve the new one */
+ tp_conn_iface_avatars_request_avatar_async (priv->avatars_proxy, contact_id,
+ request_avatar_cb,
+ priv);
+ mc_account_set_avatar_token (priv->account, token);
+ changed = TRUE;
+ }
+ g_free (prev_token);
+ return changed;
+}
+
+void
+mcd_connection_close (McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ priv->abort_reason = TP_CONN_STATUS_REASON_REQUESTED;
+ mcd_mission_abort (MCD_MISSION (connection));
+}
+
+/**
+ * mcd_connection_account_changed:
+ * @connection: the #McdConnection.
+ *
+ * This function must be called when the account this connection refers to is
+ * modified.
+ * Note: ideally, this should be a private method and the connection should
+ * monitor the account itself; but since the monitoring is already done by
+ * McdMaster for all accounts, it seemed more convenient to let it call this
+ * function whenever needed.
+ */
+void
+mcd_connection_account_changed (McdConnection *connection)
+{
+ McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
+ /* setup the avatar (if it has not been changed, this function does
+ * nothing) */
+ if (priv->tp_conn)
+ _mcd_connection_setup_avatar (priv);
+ /* TODO: same for display name, aka alias */
+}
+
diff --git a/src/mcd-connection.h b/src/mcd-connection.h
new file mode 100644
index 00000000..28e6518c
--- /dev/null
+++ b/src/mcd-connection.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MCD_CONNECTION_H__
+#define __MCD_CONNECTION_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libtelepathy/tp-connmgr.h>
+
+#include "mcd-operation.h"
+
+G_BEGIN_DECLS
+#define MCD_TYPE_CONNECTION (mcd_connection_get_type())
+#define MCD_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MCD_TYPE_CONNECTION, McdConnection))
+#define MCD_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MCD_TYPE_CONNECTION, McdConnectionClass))
+#define MCD_IS_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MCD_TYPE_CONNECTION))
+#define MCD_IS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MCD_TYPE_CONNECTION))
+#define MCD_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MCD_TYPE_CONNECTION, McdConnectionClass))
+ typedef struct
+{
+ McdOperation parent;
+} McdConnection;
+
+typedef struct
+{
+ McdOperationClass parent_class;
+} McdConnectionClass;
+
+#include "mcd-presence-frame.h"
+#include "mcd-dispatcher.h"
+
+GType mcd_connection_get_type (void);
+
+McdConnection *mcd_connection_new (DBusGConnection * dbus_connection,
+ const gchar * bus_name,
+ TpConnMgr * tp_conn_mgr,
+ McAccount * account,
+ McdPresenceFrame * presence_frame,
+ McdDispatcher *dispatcher);
+
+/* Return the connection's account */
+const McAccount *mcd_connection_get_account (McdConnection * connection);
+
+TelepathyConnectionStatus mcd_connection_get_connection_status (McdConnection
+ * connection);
+
+gboolean mcd_connection_request_channel (McdConnection *connection,
+ const struct mcd_channel_request *req,
+ GError ** error);
+
+gboolean mcd_connection_cancel_channel_request (McdConnection *connection,
+ guint operation_id,
+ const gchar *requestor_client_id,
+ GError **error);
+
+gboolean mcd_connection_get_telepathy_details (McdConnection * id,
+ gchar ** ret_servname,
+ gchar ** ret_objpath);
+
+gboolean mcd_connection_remote_avatar_changed (McdConnection *connection,
+ guint contact_id,
+ const gchar *token);
+void mcd_connection_account_changed (McdConnection *connection);
+
+void mcd_connection_close (McdConnection *connection);
+
+G_END_DECLS
+#endif /* __MCD_CONNECTION_H__ */
diff --git a/src/mcd-controller.c b/src/mcd-controller.c
new file mode 100644
index 00000000..6a8e5faa
--- /dev/null
+++ b/src/mcd-controller.c
@@ -0,0 +1,129 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "mcd-controller.h"
+
+/* Milliseconds to wait for Connectivity coming back up before exiting MC */
+#define EXIT_COUNTDOWN_TIME 5000
+
+#define MCD_CONTROLLER_PRIV(controller) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((controller), \
+ MCD_TYPE_CONTROLLER, \
+ McdControllerPrivate))
+
+/**
+ * McdController:
+ * This class implements the logic to control mission-control based on all
+ * external device events and states. It also controls mission-control
+ * life-cycle based on such events.
+ */
+G_DEFINE_TYPE (McdController, mcd_controller, MCD_TYPE_OPERATION);
+
+/* Private */
+typedef struct _McdControllerPrivate
+{
+ /* Current pending sleep timer */
+ gint shutdown_timeout_id;
+
+ gboolean is_disposed;
+} McdControllerPrivate;
+
+static void
+mcd_controller_class_init (McdControllerClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McdControllerPrivate));
+}
+
+static void
+mcd_controller_init (McdController * obj)
+{
+}
+
+/* Public */
+
+McdController *
+mcd_controller_new ()
+{
+ McdController *obj;
+ obj = MCD_CONTROLLER (g_object_new (MCD_TYPE_CONTROLLER, NULL));
+ return obj;
+}
+
+static gboolean
+_mcd_controller_exit_by_timeout (gpointer data)
+{
+ McdController *controller;
+ McdControllerPrivate *priv;
+
+ controller = MCD_CONTROLLER (data);
+ priv = MCD_CONTROLLER_PRIV (controller);
+
+ priv->shutdown_timeout_id = 0;
+
+ /* Notify sucide */
+ mcd_mission_abort (MCD_MISSION (controller));
+
+ return FALSE;
+}
+
+void
+mcd_controller_shutdown (McdController *controller, const gchar *reason)
+{
+ g_return_if_fail (MCD_IS_CONTROLLER (controller));
+
+ McdControllerPrivate *priv = MCD_CONTROLLER_PRIV (controller);
+
+ if(!priv->shutdown_timeout_id)
+ {
+ g_debug ("MC will bail out because of \"%s\" out exit after %i",
+ reason ? reason : "No reason specified",
+ EXIT_COUNTDOWN_TIME);
+
+ priv->shutdown_timeout_id = g_timeout_add (EXIT_COUNTDOWN_TIME,
+ _mcd_controller_exit_by_timeout,
+ controller);
+ }
+ else
+ {
+ g_debug ("Already shutting down. This one has the reason %s",
+ reason ? reason:"No reason specified");
+ }
+ mcd_debug_print_tree (controller);
+}
+
+void
+mcd_controller_cancel_shutdown (McdController *controller)
+{
+ g_return_if_fail (MCD_IS_CONTROLLER (controller));
+
+ McdControllerPrivate *priv = MCD_CONTROLLER_PRIV (controller);
+
+ if (priv->shutdown_timeout_id)
+ {
+ g_debug ("Cancelling exit timeout");
+ g_source_remove (priv->shutdown_timeout_id);
+ priv->shutdown_timeout_id = 0;
+ }
+}
diff --git a/src/mcd-controller.h b/src/mcd-controller.h
new file mode 100644
index 00000000..1695dcc7
--- /dev/null
+++ b/src/mcd-controller.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_CONTROLLER_H
+#define MCD_CONTROLLER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mcd-operation.h"
+
+G_BEGIN_DECLS
+
+#define MCD_TYPE_CONTROLLER (mcd_controller_get_type ())
+#define MCD_CONTROLLER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_CONTROLLER, McdController))
+#define MCD_CONTROLLER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_CONTROLLER, McdControllerClass))
+#define MCD_IS_CONTROLLER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_CONTROLLER))
+#define MCD_IS_CONTROLLER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_CONTROLLER))
+#define MCD_CONTROLLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_CONTROLLER, McdControllerClass))
+
+typedef struct _McdController McdController;
+typedef struct _McdControllerClass McdControllerClass;
+
+struct _McdController
+{
+ McdOperation parent;
+};
+
+struct _McdControllerClass
+{
+ McdOperationClass parent_class;
+};
+
+GType mcd_controller_get_type (void);
+McdController *mcd_controller_new (void);
+void mcd_controller_shutdown (McdController *controller, const gchar *reason);
+void mcd_controller_cancel_shutdown (McdController *controller);
+
+G_END_DECLS
+
+#endif /* MCD_CONTROLLER_H */
diff --git a/src/mcd-debug.c b/src/mcd-debug.c
new file mode 100644
index 00000000..27a10cd9
--- /dev/null
+++ b/src/mcd-debug.c
@@ -0,0 +1,115 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include "mcd-debug.h"
+#include "mcd-operation.h"
+
+static gint mc_debug = 0;
+
+void
+mcd_debug_ref (gpointer obj, const gchar *filename, gint linenum)
+{
+ /* Function reference untouchable by macro processing */
+ gpointer (*untouchable_ref) (gpointer object);
+
+ untouchable_ref = g_object_ref;
+ if (mc_debug >= 2)
+ g_debug ("[%s:%d]: Referencing (%d) object %p of type %s",
+ filename, linenum, G_OBJECT (obj)->ref_count,
+ obj, G_OBJECT_TYPE_NAME(obj));
+ untouchable_ref (obj);
+}
+
+void
+mcd_debug_unref (gpointer obj, const gchar *filename, gint linenum)
+{
+ void (*untouchable_unref) (gpointer object);
+
+ untouchable_unref = g_object_unref;
+ if (mc_debug >= 2)
+ g_debug ("[%s:%d]: Unreferencing (%d) object %p of type %s",
+ filename, linenum, G_OBJECT (obj)->ref_count, obj,
+ G_OBJECT_TYPE_NAME(obj));
+ untouchable_unref (obj);
+}
+
+static void
+mcd_debug_print_tree_real (gpointer object, gint level)
+{
+ GString *indent_str;
+ gchar *indent = " ";
+ gint i;
+
+ indent_str = g_string_new ("");
+
+ for (i = 0; i < level; i++)
+ {
+ g_string_append (indent_str, indent);
+ }
+
+ g_debug ("%s%s (%p): %d", indent_str->str,
+ G_OBJECT_TYPE_NAME(object), object, G_OBJECT (object)->ref_count);
+
+ if (MCD_IS_OPERATION (object))
+ {
+ const GList *missions = mcd_operation_get_missions (MCD_OPERATION (object));
+ const GList *node = missions;
+ while (node)
+ {
+ mcd_debug_print_tree_real (node->data, level + 1);
+ node = g_list_next (node);
+ }
+ }
+ g_string_free (indent_str, TRUE);
+}
+
+void
+mcd_debug_print_tree (gpointer object)
+{
+ g_return_if_fail (MCD_IS_MISSION (object));
+
+ if (mc_debug >= 2)
+ {
+ g_debug ("Object Hierarchy of object %p", object);
+ g_debug ("[");
+ mcd_debug_print_tree_real (object, 1);
+ g_debug ("]");
+ }
+}
+
+void mcd_debug_init ()
+{
+ gchar *mc_debug_str;
+
+ mc_debug_str = getenv ("MC_DEBUG");
+ if (mc_debug_str)
+ mc_debug = atoi (mc_debug_str);
+}
+
+inline gint mcd_debug_get_level ()
+{
+ return mc_debug;
+}
+
diff --git a/src/mcd-debug.h b/src/mcd-debug.h
new file mode 100644
index 00000000..8b3318f0
--- /dev/null
+++ b/src/mcd-debug.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MCD_DEBUG_H__
+#define __MCD_DEBUG_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define g_object_ref(obj) (mcd_debug_ref (obj, __FILE__, __LINE__))
+#define g_object_unref(obj) (mcd_debug_unref (obj, __FILE__, __LINE__))
+
+void mcd_debug_init ();
+
+inline gint mcd_debug_get_level ();
+
+void mcd_debug_ref (gpointer obj, const gchar *filename, gint linenum);
+void mcd_debug_unref (gpointer obj, const gchar *filename, gint linenum);
+
+void mcd_debug_print_tree (gpointer obj);
+
+G_END_DECLS
+
+#endif /* __MCD_DEBUG_H__ */
diff --git a/src/mcd-dispatcher-context.h b/src/mcd-dispatcher-context.h
new file mode 100644
index 00000000..718220a5
--- /dev/null
+++ b/src/mcd-dispatcher-context.h
@@ -0,0 +1,138 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __MCD_DISPATCHER_CONTEXT_H__
+#define __MCD_DISPATCHER_CONTEXT_H__
+
+#include "mcd-dispatcher.h"
+#include "mcd-connection.h"
+#include "mcd-chan-handler.h"
+
+G_BEGIN_DECLS
+
+#define MCD_PLUGIN_INIT_FUNC "mcd_filters_init"
+
+/* Filter flag definitions */
+#define MCD_FILTER_IN 1<<0
+#define MCD_FILTER_OUT 1<<1
+
+/* The context of the current filter chain execution. Should be kept
+ * intact by filter implementation and passed transparently to
+ * getters/setters and state machine functions
+ */
+typedef struct _McdDispatcherContext McdDispatcherContext;
+
+/* Filter function type */
+typedef void (*filter_func_t) (McdDispatcherContext * ctx);
+
+/* Data structures and typedefs needed by pluginized filters */
+typedef void (*abort_function_t) (McdDispatcherContext * ctx);
+
+/* Requests the chain of filter functions for an unique combination of
+ * channel types and filter flags.
+ *
+ * @param channel_type: A quark representing a particular channel type
+ * @param filter_flags: The flags for the filter, such as incoming/outgoing
+ * @return A NULL-terminated array of filter function pointers
+ */
+
+filter_func_t *mcd_dispatcher_get_filter_chain (McdDispatcher * dispatcher,
+ GQuark channel_type_quark,
+ guint filter_flags);
+
+
+/* Indicates to Mission Control that we want to register a filter chain
+ * for a unique combination of channel type/filter flags.
+ *
+ * @param channel_type_quark: Quark indicating the channel type
+ * @param filter_flags: The flags for the filter, such as incoming/outgoing
+ * @param chain: The chain of filter functions to register
+ */
+
+void mcd_dispatcher_register_filter_chain (McdDispatcher * dispatcher,
+ GQuark channel_type_quark,
+ guint filter_flags,
+ filter_func_t * chain);
+
+/* Indicates to Mission Control that we will not want to have a filter chain
+ * for particular unique channel type/filter flags combination anymore.
+ *
+ * @param channel_type_quark: Quark indicating the channel type
+ * @param filter_flags: The flags for the filter, such as incoming/outgoing
+ */
+void mcd_dispatcher_unregister_filter_chain (McdDispatcher * dispatcher,
+ GQuark channel_type_quark,
+ guint filter_flags);
+
+/* Context API section
+ *
+ * The use of gpointer is intentional; we want to make accessing the
+ * internals of the context restricted to make it unlikely that
+ * somebody shoots [him|her]self in the foot while doing fancy
+ * tricks. This also minimizes the amount of necessary includes.
+ */
+
+/* Getters */
+
+McdDispatcher* mcd_dispatcher_context_get_dispatcher (McdDispatcherContext * ctx);
+
+const TpChan *mcd_dispatcher_context_get_channel_object (McdDispatcherContext * ctx);
+
+const TpConn * mcd_dispatcher_context_get_connection_object (McdDispatcherContext * ctx);
+
+McdChannel * mcd_dispatcher_context_get_channel (McdDispatcherContext * ctx);
+
+const McdConnection * mcd_dispatcher_context_get_connection (McdDispatcherContext * ctx);
+
+McdChannelHandler * mcd_dispatcher_context_get_chan_handler (McdDispatcherContext * ctx);
+
+/*Returns an array of the gchar * addresses of participants in the channel*/
+GPtrArray *mcd_dispatcher_context_get_members (McdDispatcherContext * ctx);
+
+/*Filter-specifc data*/
+gpointer mcd_dispatcher_context_get_data (McdDispatcherContext * ctx);
+
+
+/* Setters */
+
+/* Abort function should be known only to the filter function. When
+ executed, filter function MUST set an abort fn as needed (such as
+ when implementing an async filter) */
+
+void mcd_dispatcher_context_set_abort_fn (McdDispatcherContext * ctx, abort_function_t abort_fn);
+
+void mcd_dispatcher_context_set_data (McdDispatcherContext * ctx, gpointer data);
+
+/* Statemachine API section */
+
+/* Will step through the state machine.
+ * @param ctx: The context
+ * @param result: The return code
+ */
+
+void mcd_dispatcher_context_process (McdDispatcherContext * ctx, gboolean result);
+
+G_END_DECLS
+
+#endif
diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
new file mode 100644
index 00000000..1c6aa217
--- /dev/null
+++ b/src/mcd-dispatcher.c
@@ -0,0 +1,1185 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <dlfcn.h>
+#include <glib/gi18n.h>
+#include <libtelepathy/tp-chan-iface-group-gen.h>
+#include <libtelepathy/tp-ch-gen.h>
+
+#include "mcd-signals-marshal.h"
+#include "mcd-connection.h"
+#include "mcd-channel.h"
+#include "mcd-master.h"
+#include "mcd-chan-handler.h"
+#include "mcd-dispatcher-context.h"
+
+#define MCD_DISPATCHER_PRIV(dispatcher) (G_TYPE_INSTANCE_GET_PRIVATE ((dispatcher), \
+ MCD_TYPE_DISPATCHER, \
+ McdDispatcherPrivate))
+
+G_DEFINE_TYPE (McdDispatcher, mcd_dispatcher, MCD_TYPE_MISSION);
+
+struct _McdDispatcherContext
+{
+ McdDispatcher *dispatcher;
+
+ /*The actual channel */
+ McdChannel *channel;
+
+ /* State-machine internal data fields: */
+ filter_func_t *chain;
+
+ /* Next function in chain */
+ guint next_func_index;
+
+ /* Function to abort the current filter, if any */
+ abort_function_t abort_fn;
+
+ /*Filter-specific user data */
+ gpointer data;
+
+};
+
+typedef struct _McdDispatcherPrivate
+{
+ /* Pending state machine contexts */
+ GSList *state_machine_list;
+
+ /* All active channels */
+ GList *channels;
+
+ GSList *filter_dlhandles;
+ gchar *plugin_dir;
+ GData *interface_filters;
+ DBusGConnection *dbus_connection;
+
+ /* Channel handlers */
+ GHashTable *channel_handler_hash;
+ /* Array of channel handler's capabilities, stored as a GPtrArray for
+ * performance reasons */
+ GPtrArray *channel_handler_caps;
+
+ McdMaster *master;
+
+ gboolean is_disposed;
+
+} McdDispatcherPrivate;
+
+struct iface_chains_t
+{
+ filter_func_t *chain_in;
+ filter_func_t *chain_out;
+};
+
+enum
+{
+ PROP_0,
+ PROP_PLUGIN_DIR,
+ PROP_DBUS_CONNECTION,
+ PROP_MCD_MASTER,
+};
+
+enum _McdDispatcherSignalType
+{
+ CHANNEL_ADDED,
+ CHANNEL_REMOVED,
+ DISPATCHED,
+ DISPATCH_FAILED,
+ LAST_SIGNAL
+};
+
+static guint mcd_dispatcher_signals[LAST_SIGNAL] = { 0 };
+
+static void mcd_dispatcher_context_free (McdDispatcherContext * ctx);
+
+static void
+_mcd_dispatcher_load_filters (McdDispatcher * dispatcher)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+ GDir *dir = NULL;
+ GError *error = NULL;
+ void *plugin_handle;
+ const gchar *name;
+
+ dir = g_dir_open (priv->plugin_dir, 0, &error);
+ if (!dir)
+ {
+ g_debug ("Could not open plugin directory: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ while ((name = g_dir_read_name (dir)))
+ {
+ plugin_handle = NULL;
+ gchar *path = NULL;
+ path = g_strconcat (priv->plugin_dir, G_DIR_SEPARATOR_S, name, NULL);
+ /* Skip directories */
+
+ if (g_file_test (path, G_FILE_TEST_IS_DIR))
+ {
+ g_free (path);
+ continue;
+ }
+ /* Is it a library? If yes, add the name to list */
+
+ if (!g_str_has_suffix (path, ".so"))
+ {
+ g_free (path);
+ continue;
+ }
+
+ /* ? Do we need to check more strictly than by using prefix-check?
+ * Probably not, as failure of dlopen will take care of things
+ * anyway? */
+
+ plugin_handle = dlopen (path, RTLD_NOW);
+
+ if (plugin_handle != NULL)
+ {
+ void (*plugin_init) (McdDispatcher * dispatcher);
+
+ priv->filter_dlhandles = g_slist_prepend (priv->filter_dlhandles,
+ plugin_handle);
+
+ plugin_init = dlsym (plugin_handle, MCD_PLUGIN_INIT_FUNC);
+ if (plugin_init != NULL)
+ {
+ plugin_init (dispatcher);
+ }
+ else
+ {
+ g_debug ("Error opening filter plugin: %s: %s", path,
+ dlerror ());
+ }
+ }
+ else
+ {
+ g_debug ("Could not open plugin %s because: %s", path, dlerror ());
+ }
+ g_free (path);
+ }
+ g_dir_close (dir);
+
+ return;
+}
+
+static void
+_mcd_dispatcher_unload_filters (McdDispatcher * dispatcher)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ if (priv->filter_dlhandles)
+ {
+ g_slist_foreach (priv->filter_dlhandles, (GFunc) dlclose, NULL);
+ g_slist_free (priv->filter_dlhandles);
+ priv->filter_dlhandles = NULL;
+
+ g_datalist_clear (&priv->interface_filters);
+ priv->interface_filters = NULL;
+ }
+}
+
+/* REGISTRATION/DEREGISTRATION of filters*/
+
+/* A convenience function for acquiring the chain for particular channel
+type and filter flag combination. */
+
+static filter_func_t *
+_mcd_dispatcher_get_filter_chain (McdDispatcher * dispatcher,
+ GQuark channel_type_quark,
+ guint filter_flags)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+ struct iface_chains_t *iface_chains;
+ filter_func_t *filter_chain = NULL;
+
+ iface_chains =
+ (struct iface_chains_t *)
+ g_datalist_id_get_data (&(priv->interface_filters), channel_type_quark);
+
+ if (iface_chains == NULL)
+ {
+ g_debug ("%s: No chains for interface %s", G_STRFUNC,
+ g_quark_to_string (channel_type_quark));
+ }
+ else
+ switch (filter_flags)
+ {
+ case MCD_FILTER_IN:
+ filter_chain = iface_chains->chain_in;
+ break;
+ case MCD_FILTER_OUT:
+ filter_chain = iface_chains->chain_out;
+ break;
+
+ default:
+ g_warning ("Unsupported filter flag value");
+ break;
+ }
+
+ return filter_chain;
+}
+
+void
+mcd_dispatcher_register_filter_chain (McdDispatcher * dispatcher,
+ GQuark channel_type_quark,
+ guint filter_flags,
+ filter_func_t * chain)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+ struct iface_chains_t *iface_chains = NULL;
+
+ /* Check if the interface already has stored data, otherwise create it */
+
+ if (!(iface_chains = g_datalist_id_get_data (&(priv->interface_filters),
+ channel_type_quark)))
+ {
+ iface_chains = g_new0 (struct iface_chains_t, 1);
+ g_datalist_id_set_data_full (&(priv->interface_filters),
+ channel_type_quark, iface_chains, g_free);
+ }
+
+ switch (filter_flags)
+ {
+ case MCD_FILTER_IN:
+ if (iface_chains->chain_in != NULL)
+ {
+ g_warning
+ ("Overwriting a previous chain without unregistering it!");
+ }
+ iface_chains->chain_in = chain;
+ break;
+ case MCD_FILTER_OUT:
+ if (iface_chains->chain_out != NULL)
+ {
+ g_warning
+ ("Overwriting a previous chain without unregistering it!");
+ }
+ iface_chains->chain_out = chain;
+ break;
+ default:
+ g_warning ("Unknown filter flag value!");
+ }
+}
+
+void
+mcd_dispatcher_unregister_filter_chain (McdDispatcher * dispatcher,
+ GQuark channel_type_quark,
+ guint filter_flags)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ /* First, do we have anything registered for that channel type? */
+ struct iface_chains_t *chains =
+ (struct iface_chains_t *)
+ g_datalist_id_get_data (&(priv->interface_filters),
+ channel_type_quark);
+ if (chains == NULL)
+ {
+ g_warning ("Attempting to unregister a nonexisting filter chain");
+ return;
+ }
+
+ switch (filter_flags)
+ {
+ case MCD_FILTER_IN:
+ /* No worries about memory leaks, as these are function pointers */
+ chains->chain_in = NULL;
+ break;
+ case MCD_FILTER_OUT:
+ chains->chain_out = NULL;
+ break;
+ default:
+ g_warning ("Unknown filter flag value!");
+ }
+
+ /* Both chains are unregistered? We may as well free the struct then */
+
+ if (chains->chain_in == NULL && chains->chain_out == NULL)
+ {
+ /* ? Should we dlclose the plugin as well..? */
+ g_datalist_id_remove_data (&(priv->interface_filters),
+ channel_type_quark);
+ g_free (chains);
+ }
+
+ return;
+}
+
+/* Returns # of times particular channel type has been used */
+gint
+mcd_dispatcher_get_channel_type_usage (McdDispatcher * dispatcher,
+ GQuark chan_type_quark)
+{
+ GList *node;
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+ gint usage_counter = 0;
+
+ node = priv->channels;
+ while (node)
+ {
+ McdChannel *chan = (McdChannel*) node->data;
+ if (chan && chan_type_quark == mcd_channel_get_channel_type_quark (chan))
+ usage_counter++;
+ node = node->next;
+ }
+
+ return usage_counter;
+}
+
+/* The callback is called on channel Closed signal */
+static void
+on_channel_abort_list (McdChannel *channel, McdDispatcher *dispatcher)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ g_debug ("Abort Channel; Removing channel from list");
+ priv->channels = g_list_remove (priv->channels, channel);
+ g_signal_emit_by_name (dispatcher, "channel-removed", channel);
+ g_object_unref (channel);
+}
+
+static void
+on_master_abort (McdMaster *master, McdDispatcherPrivate *priv)
+{
+ g_object_unref (master);
+ priv->master = NULL;
+}
+
+/* CHANNEL HANDLING */
+
+/* Ensure that when the channelhandler dies, the channels do not be
+ * left around (e.g. when VOIP UI dies, the call used to hang
+ * around)
+ */
+static void
+_mcd_dispatcher_channel_handler_destroy_cb (DBusGProxy * channelhandler,
+ gpointer userdata)
+{
+ McdChannel *channel;
+
+ /* If the channel has already been destroyed, do not bother doing
+ * anything. */
+ if (!userdata || !(G_IS_OBJECT (userdata)) || !(MCD_IS_CHANNEL (userdata)))
+ {
+ g_debug ("Channel has already been closed. No need to clean up.");
+ return;
+ }
+
+ channel = MCD_CHANNEL (userdata);
+
+ g_debug ("Channelhandler object been destroyed, chan still valid.");
+ mcd_mission_abort (MCD_MISSION (channel));
+}
+
+static void
+disconnect_proxy_destry_cb (McdChannel *channel, DBusGProxy *channelhandler)
+{
+ g_signal_handlers_disconnect_by_func (channelhandler,
+ _mcd_dispatcher_channel_handler_destroy_cb,
+ channel);
+ g_object_unref (channelhandler);
+}
+
+static void
+cancel_proxy_call (McdChannel *channel, DBusGProxyCall *call)
+{
+ DBusGProxy *proxy = g_object_steal_data (G_OBJECT (channel),
+ "cancel_proxy_call_userdata");
+ dbus_g_proxy_cancel_call (proxy, call);
+}
+
+static void
+_mcd_dispatcher_handle_channel_async_cb (DBusGProxy * proxy, GError * error,
+ gpointer userdata)
+{
+ McdDispatcherContext *context = userdata;
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (context->dispatcher);
+ McdChannel *channel;
+
+ channel = mcd_dispatcher_context_get_channel (context);
+ McdChannelHandler *chandler = g_hash_table_lookup (priv->channel_handler_hash,
+ mcd_channel_get_channel_type (channel));
+
+ g_object_steal_data (G_OBJECT (channel), "cancel_proxy_call_userdata");
+ g_signal_handlers_disconnect_matched (channel, G_SIGNAL_MATCH_FUNC, 0, 0,
+ NULL, cancel_proxy_call, NULL);
+
+ /* We'll no longer need this proxy instance. */
+ if (proxy && DBUS_IS_G_PROXY (proxy))
+ {
+ g_object_unref (proxy);
+ }
+
+ if (error != NULL)
+ {
+ GError *mc_error = NULL;
+
+ g_warning ("Handle channel failed: %s", error->message);
+
+ /* We can't reliably map channel handler error codes to MC error
+ * codes. So just using generic error message.
+ */
+ mc_error = g_error_new (MC_ERROR, MC_CHANNEL_REQUEST_GENERIC_ERROR,
+ "Handle channel failed: %s", error->message);
+
+ g_signal_emit_by_name (context->dispatcher, "dispatch-failed",
+ context->channel, mc_error);
+
+ g_error_free (mc_error);
+ g_error_free (error);
+ if (context->channel)
+ mcd_mission_abort (MCD_MISSION (context->channel));
+ return;
+ }
+
+ /* In case the VOIP channel handler dies unexpectedly, we
+ * may end up in very confused state if we do
+ * nothing. Thus, we'll try to handle the death */
+
+ if (mcd_channel_get_channel_type_quark (channel)
+ == TELEPATHY_CHAN_IFACE_STREAMED_QUARK)
+ {
+ const McdConnection *connection;
+ DBusGConnection *dbus_connection;
+ GError *unique_proxy_error = NULL;
+
+ connection = mcd_dispatcher_context_get_connection (context);
+ g_object_get (G_OBJECT (connection), "dbus-connection", &dbus_connection, NULL);
+ g_debug ("Aha! A streamed media channel, need to guard it.");
+
+ DBusGProxy *unique_name_proxy =
+ dbus_g_proxy_new_for_name_owner (dbus_connection,
+ chandler->bus_name,
+ chandler->obj_path,
+ "org.freedesktop.Telepathy.ChannelHandler",
+ &unique_proxy_error);
+ if (unique_proxy_error == NULL)
+ {
+ g_debug ("Adding the destroy handler support.");
+ g_signal_connect (unique_name_proxy,
+ "destroy",
+ G_CALLBACK (_mcd_dispatcher_channel_handler_destroy_cb),
+ context->channel);
+ g_signal_connect (context->channel, "abort",
+ G_CALLBACK(disconnect_proxy_destry_cb),
+ unique_name_proxy);
+ }
+ }
+
+ g_signal_emit_by_name (context->dispatcher, "dispatched", channel);
+ mcd_dispatcher_context_free (context);
+}
+
+/* Happens at the end of successful filter chain execution (empty chain
+ * is always successful)
+ */
+static void
+_mcd_dispatcher_start_channel_handler (McdDispatcherContext * context)
+{
+ McdChannelHandler *chandler;
+ McdDispatcherPrivate *priv;
+ McdChannel *channel;
+
+ g_return_if_fail (context);
+
+ priv = MCD_DISPATCHER_PRIV (context->dispatcher);
+ channel = mcd_dispatcher_context_get_channel (context);
+
+ /* we need to know where's the channel handler and queue */
+ /* drop from the queue */
+ /*FIXME: Use Quarks in hashtable */
+ chandler =
+ g_hash_table_lookup (priv->channel_handler_hash,
+ mcd_channel_get_channel_type (channel));
+ if (chandler == NULL)
+ {
+ GError *mc_error;
+ g_debug ("No handler for channel type %s",
+ mcd_channel_get_channel_type (channel));
+
+ mc_error = g_error_new (MC_ERROR, MC_CHANNEL_REQUEST_GENERIC_ERROR,
+ "No handler for channel type %s",
+ mcd_channel_get_channel_type (channel));
+ g_signal_emit_by_name (context->dispatcher, "dispatch-failed", channel,
+ mc_error);
+ g_error_free (mc_error);
+ }
+ else
+ {
+ DBusGProxyCall *call;
+ TpConn *tp_conn;
+
+ const McdConnection *connection = mcd_dispatcher_context_get_connection (context);
+ DBusGConnection *dbus_connection;
+
+ g_object_get (G_OBJECT (connection),
+ "dbus-connection", &dbus_connection,
+ "tp-connection", &tp_conn, NULL);
+
+ DBusGProxy *handler_proxy = dbus_g_proxy_new_for_name (dbus_connection,
+ chandler->bus_name,
+ chandler->obj_path,
+ "org.freedesktop.Telepathy.ChannelHandler");
+
+ g_debug ("Starting chan handler (bus = %s, obj = '%s'): conn = %s, chan_type = %s,"
+ " obj_path = %s, handle_type = %d, handle = %d",
+ chandler->bus_name,
+ chandler->obj_path,
+ dbus_g_proxy_get_path (DBUS_G_PROXY (tp_conn)),
+ mcd_channel_get_channel_type (channel),
+ mcd_channel_get_object_path (channel),
+ mcd_channel_get_handle_type (channel),
+ mcd_channel_get_handle (channel));
+
+ call = tp_ch_handle_channel_async (handler_proxy,
+ /*Connection bus */
+ dbus_g_proxy_get_bus_name (DBUS_G_PROXY
+ (tp_conn)),
+ /*Connection path */
+ dbus_g_proxy_get_path (DBUS_G_PROXY
+ (tp_conn)),
+ /*Channel type */
+ mcd_channel_get_channel_type (channel),
+ /*Object path */
+ mcd_channel_get_object_path (channel),
+ mcd_channel_get_handle_type (channel),
+ mcd_channel_get_handle (channel),
+ _mcd_dispatcher_handle_channel_async_cb,
+ context);
+ g_object_set_data (G_OBJECT (channel), "cancel_proxy_call_userdata",
+ handler_proxy);
+ g_signal_connect (channel, "abort", G_CALLBACK(cancel_proxy_call),
+ call);
+ g_object_unref (tp_conn);
+ }
+}
+
+static void
+_mcd_dispatcher_drop_channel_handler (McdDispatcherContext * context)
+{
+ g_return_if_fail(context);
+
+ /* drop from the queue and close channel */
+
+ /* FIXME: The queue functionality is still missing. Add support for
+ it, once it's available. */
+
+ if (context->channel != NULL)
+ {
+ /* Context will be destroyed on this emission, so be careful
+ * not to access it after this.
+ */
+ mcd_mission_abort (MCD_MISSION (context->channel));
+ }
+}
+
+/* STATE MACHINE */
+
+static void
+_mcd_dispatcher_leave_state_machine (McdDispatcherContext * context)
+{
+ McdDispatcherPrivate *priv =
+ MCD_DISPATCHER_PRIV (context->dispatcher);
+
+ if (context->abort_fn)
+ context->abort_fn (context);
+
+ /* _mcd_dispatcher_drop_channel_handler (context); */
+
+ priv->state_machine_list =
+ g_slist_remove (priv->state_machine_list, context);
+
+ mcd_dispatcher_context_free (context);
+}
+
+static void
+on_channel_abort_context (McdChannel *channel, McdDispatcherContext *context)
+{
+ g_debug ("Abort Channel; Destroying state machine context.");
+ _mcd_dispatcher_leave_state_machine (context);
+}
+
+/* Entering the state machine */
+static void
+_mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
+ McdChannel *channel)
+{
+ McdDispatcherContext *context;
+ filter_func_t *chain;
+ GQuark chan_type_quark;
+ gboolean outgoing;
+ gint filter_flags;
+
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ g_object_get (G_OBJECT (channel),
+ "channel-type-quark", &chan_type_quark,
+ "outgoing", &outgoing,
+ NULL);
+
+ filter_flags = outgoing ? MCD_FILTER_OUT: MCD_FILTER_IN;
+ chain = _mcd_dispatcher_get_filter_chain (dispatcher,
+ chan_type_quark,
+ filter_flags);
+
+ /* Preparing and filling the context */
+ context = g_new0 (McdDispatcherContext, 1);
+ context->dispatcher = dispatcher;
+ context->channel = channel;
+ context->chain = chain;
+
+ /* Context must be destroyed when the channel is destroyed */
+ g_object_ref (channel); /* We hold separate refs for state machine */
+ g_signal_connect (channel, "abort", G_CALLBACK (on_channel_abort_context),
+ context);
+
+ if (chain)
+ {
+ g_debug ("entering state machine for channel of type: %s",
+ g_quark_to_string (chan_type_quark));
+
+ priv->state_machine_list =
+ g_slist_prepend (priv->state_machine_list, context);
+ mcd_dispatcher_context_process (context, TRUE);
+ }
+ else
+ {
+ g_debug ("No filters found for type %s, starting the channel handler", g_quark_to_string (chan_type_quark));
+ _mcd_dispatcher_start_channel_handler (context);
+ }
+}
+
+static gint
+channel_on_state_machine (McdDispatcherContext *context, McdChannel *channel)
+{
+ return (context->channel == channel) ? 0 : 1;
+}
+
+static void
+_mcd_dispatcher_send (McdDispatcher * dispatcher, McdChannel * channel)
+{
+ McdDispatcherPrivate *priv;
+ g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
+ g_return_if_fail (MCD_IS_CHANNEL (channel));
+
+ priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ /* it can happen that this function gets called when the same channel has
+ * already entered the state machine or even when it has already been
+ * dispatched; so, check if this channel is already known to the
+ * dispatcher: */
+ if (g_list_find (priv->channels, channel))
+ {
+ McdDispatcherContext *context = NULL;
+ GSList *list;
+ g_debug ("%s: channel is already in dispatcher", G_STRFUNC);
+
+ /* check if channel has already been dispatched (if it's still in the
+ * state machine list, this means that it hasn't) */
+ list = g_slist_find_custom (priv->state_machine_list, channel,
+ (GCompareFunc)channel_on_state_machine);
+ if (list) context = list->data;
+ if (context)
+ {
+ gboolean outgoing;
+ g_debug ("%s: channel found in the state machine (%p)", G_STRFUNC, context);
+ g_object_get (G_OBJECT (channel),
+ "outgoing", &outgoing,
+ NULL);
+
+ g_debug ("channel is %s", outgoing ? "outgoing" : "incoming");
+ /* this channel has not been dispatched; we can get to this point if:
+ * 1) the channel is incoming (i.e. the contacts plugin icon is
+ * blinking) but the user didn't realize that and instead
+ * requested the same channel again;
+ * 2) theif channel is outgoing, and it was requested again before
+ * it could be created; I'm not sure this can really happen,
+ * though. In this case we don't have to do anything, just ignore
+ * this second request */
+ if (!outgoing)
+ {
+ /* incoming channel: the state machine is probably stucked
+ * waiting for the user to acknowledge the channel. We bypass
+ * all that and instead launch the channel handler; this will
+ * free the context, but we still have to remove it from the
+ * machine state list ourselves.
+ * The filters should connect to the "dispatched" signal to
+ * catch this particular situation and clean-up gracefully. */
+ _mcd_dispatcher_start_channel_handler (context);
+ priv->state_machine_list =
+ g_slist_remove(priv->state_machine_list, context);
+
+ }
+ }
+ else
+ {
+ /* The channel was not found in the state machine, hence it must
+ * have been already dispatched.
+ * We could get to this point if the UI crashed while this channel
+ * was open, and now the user is requesting it again. just go straight
+ * and start the channel handler. */
+ g_debug ("%s: channel is already dispatched, starting handler", G_STRFUNC);
+ /* Preparing and filling the context */
+ context = g_new0 (McdDispatcherContext, 1);
+ context->dispatcher = dispatcher;
+ context->channel = channel;
+
+ /* We must ref() the channel, because mcd_dispatcher_context_free()
+ * will unref() it */
+ g_object_ref (channel);
+ _mcd_dispatcher_start_channel_handler (context);
+ }
+ return;
+ }
+
+ /* Get hold of it in our all channels list */
+ g_object_ref (channel); /* We hold separate refs for channels list */
+ g_signal_connect (channel, "abort", G_CALLBACK (on_channel_abort_list),
+ dispatcher);
+ priv->channels = g_list_prepend (priv->channels, channel);
+
+ g_signal_emit_by_name (dispatcher, "channel-added", channel);
+ _mcd_dispatcher_enter_state_machine (dispatcher, channel);
+}
+
+static void
+_mcd_dispatcher_set_property (GObject * obj, guint prop_id,
+ const GValue * val, GParamSpec * pspec)
+{
+ McdDispatcher *dispatcher = MCD_DISPATCHER (obj);
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (obj);
+ DBusGConnection *dbus_connection;
+ McdMaster *master;
+
+ switch (prop_id)
+ {
+ case PROP_PLUGIN_DIR:
+ g_free (priv->plugin_dir);
+
+ priv->plugin_dir = g_value_dup_string (val);
+
+ _mcd_dispatcher_unload_filters (dispatcher);
+ _mcd_dispatcher_load_filters (dispatcher);
+ break;
+ case PROP_DBUS_CONNECTION:
+ dbus_connection = g_value_get_pointer (val);
+ dbus_g_connection_ref (dbus_connection);
+ if (priv->dbus_connection)
+ dbus_g_connection_unref (priv->dbus_connection);
+ priv->dbus_connection = dbus_connection;
+ break;
+ case PROP_MCD_MASTER:
+ master = g_value_get_object (val);
+ g_object_ref (G_OBJECT (master));
+ if (priv->master)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (master), G_CALLBACK (on_master_abort), NULL);
+ g_object_unref (priv->master);
+ }
+ priv->master = master;
+ g_signal_connect (G_OBJECT (master), "abort", G_CALLBACK (on_master_abort), priv);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_dispatcher_get_property (GObject * obj, guint prop_id,
+ GValue * val, GParamSpec * pspec)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_PLUGIN_DIR:
+ g_value_set_string (val, priv->plugin_dir);
+ break;
+ case PROP_DBUS_CONNECTION:
+ g_value_set_pointer (val, priv->dbus_connection);
+ break;
+ case PROP_MCD_MASTER:
+ g_value_set_object (val, priv->master);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_dispatcher_finalize (GObject * object)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (object);
+ GType type;
+ gint i;
+
+ g_hash_table_destroy (priv->channel_handler_hash);
+
+ type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING,
+ G_TYPE_UINT, G_TYPE_INVALID);
+ for (i = 0; i < priv->channel_handler_caps->len; i++)
+ g_boxed_free (type, g_ptr_array_index (priv->channel_handler_caps, i));
+ g_ptr_array_free (priv->channel_handler_caps, TRUE);
+
+ G_OBJECT_CLASS (mcd_dispatcher_parent_class)->finalize (object);
+}
+
+static void
+_mcd_dispatcher_dispose (GObject * object)
+{
+ McdDispatcher *dispatcher = MCD_DISPATCHER (object);
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+ priv->is_disposed = TRUE;
+
+ if (priv->master)
+ {
+ g_object_unref (priv->master);
+ priv->master = NULL;
+ }
+
+ if (priv->dbus_connection)
+ {
+ dbus_g_connection_unref (priv->dbus_connection);
+ priv->dbus_connection = NULL;
+ }
+
+ if (priv->channels)
+ {
+ g_list_free (priv->channels);
+ priv->channels = NULL;
+ }
+ g_free (priv->plugin_dir);
+ priv->plugin_dir = NULL;
+
+ _mcd_dispatcher_unload_filters (dispatcher);
+ G_OBJECT_CLASS (mcd_dispatcher_parent_class)->dispose (object);
+}
+
+gboolean
+mcd_dispatcher_send (McdDispatcher * dispatcher, McdChannel *channel)
+{
+ g_return_val_if_fail (MCD_IS_DISPATCHER (dispatcher), FALSE);
+ g_return_val_if_fail (MCD_IS_CHANNEL (channel), FALSE);
+ MCD_DISPATCHER_GET_CLASS (dispatcher)->send (dispatcher, channel);
+ return TRUE;
+}
+
+static void
+mcd_dispatcher_class_init (McdDispatcherClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (McdDispatcherPrivate));
+
+ object_class->set_property = _mcd_dispatcher_set_property;
+ object_class->get_property = _mcd_dispatcher_get_property;
+ object_class->finalize = _mcd_dispatcher_finalize;
+ object_class->dispose = _mcd_dispatcher_dispose;
+ klass->send = _mcd_dispatcher_send;
+
+ mcd_dispatcher_signals[CHANNEL_ADDED] =
+ g_signal_new ("channel_added",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (McdDispatcherClass,
+ channel_added_signal),
+ NULL, NULL, mcd_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, MCD_TYPE_CHANNEL);
+
+ mcd_dispatcher_signals[CHANNEL_REMOVED] =
+ g_signal_new ("channel_removed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (McdDispatcherClass,
+ channel_removed_signal),
+ NULL, NULL, mcd_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, MCD_TYPE_CHANNEL);
+
+ mcd_dispatcher_signals[DISPATCHED] =
+ g_signal_new ("dispatched",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (McdDispatcherClass,
+ dispatched_signal),
+ NULL, NULL, mcd_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, MCD_TYPE_CHANNEL);
+
+ mcd_dispatcher_signals[DISPATCH_FAILED] =
+ g_signal_new ("dispatch-failed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (McdDispatcherClass,
+ dispatch_failed_signal),
+ NULL, NULL, mcd_marshal_VOID__OBJECT_POINTER,
+ G_TYPE_NONE, 2, MCD_TYPE_CHANNEL, G_TYPE_POINTER);
+
+ /* Properties */
+ g_object_class_install_property (object_class,
+ PROP_PLUGIN_DIR,
+ g_param_spec_string ("plugin-dir",
+ _("Plugin Directory"),
+ _("The Directory to load filter plugins from"),
+ MCD_DEFAULT_FILTER_PLUGIN_DIR,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_DBUS_CONNECTION,
+ g_param_spec_pointer ("dbus-connection",
+ _("DBus Connection"),
+ _("DBus connection to use by us"),
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_MCD_MASTER,
+ g_param_spec_object ("mcd-master",
+ _("McdMaster"),
+ _("McdMaster"),
+ MCD_TYPE_MASTER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+_build_channel_capabilities (gchar *channel_type, McdChannelHandler *handler,
+ GPtrArray *capabilities)
+{
+ GValue cap = {0,};
+ GType cap_type;
+
+ cap_type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING,
+ G_TYPE_UINT, G_TYPE_INVALID);
+ g_value_init (&cap, cap_type);
+ g_value_take_boxed (&cap, dbus_g_type_specialized_construct (cap_type));
+
+ dbus_g_type_struct_set (&cap,
+ 0, channel_type,
+ 1, handler->capabilities,
+ G_MAXUINT);
+
+ g_ptr_array_add (capabilities, g_value_get_boxed (&cap));
+}
+
+
+
+static void
+mcd_dispatcher_init (McdDispatcher * dispatcher)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ priv->plugin_dir = g_strdup (MCD_DEFAULT_FILTER_PLUGIN_DIR);
+
+ g_datalist_init (&(priv->interface_filters));
+
+ priv->channel_handler_hash = mcd_get_channel_handlers ();
+
+ priv->channel_handler_caps = g_ptr_array_new();
+ g_hash_table_foreach (priv->channel_handler_hash,
+ (GHFunc)_build_channel_capabilities,
+ priv->channel_handler_caps);
+
+ _mcd_dispatcher_load_filters (dispatcher);
+}
+
+McdDispatcher *
+mcd_dispatcher_new (DBusGConnection * dbus_connection, McdMaster * master)
+{
+ McdDispatcher *obj;
+ obj = MCD_DISPATCHER (g_object_new (MCD_TYPE_DISPATCHER,
+ "dbus-connection",
+ dbus_connection,
+ "mcd-master",
+ master,
+ NULL));
+ return obj;
+}
+
+/* The new state machine walker function for pluginized filters*/
+
+void
+mcd_dispatcher_context_process (McdDispatcherContext * context, gboolean result)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (context->dispatcher);
+
+ if (result)
+ {
+ /* Do we still have functions to go through? */
+ if (context->chain[context->next_func_index])
+ {
+ filter_func_t filter = context->chain[context->next_func_index];
+
+ context->next_func_index++;
+
+ /*new state-new abort function*/
+ context->abort_fn = NULL;
+ g_debug ("Next filter");
+ filter (context);
+ return; /*State machine goes on...*/
+ }
+ else
+ {
+ /* Context would be destroyed somewhere in this call */
+ _mcd_dispatcher_start_channel_handler (context);
+ }
+ }
+ else
+ {
+ g_debug ("Filters failed, disposing request");
+
+ /* Some filter failed. The request shall not be handled. */
+ /* Context would be destroyed somewhere in this call */
+ _mcd_dispatcher_drop_channel_handler (context);
+ }
+
+ /* FIXME: Should we remove the request in other cases? */
+ priv->state_machine_list =
+ g_slist_remove(priv->state_machine_list, context);
+}
+
+static void
+mcd_dispatcher_context_free (McdDispatcherContext * context)
+{
+ /* FIXME: check for leaks */
+ g_return_if_fail (context);
+
+ /* Freeing context data */
+ if (context->channel)
+ {
+ g_signal_handlers_disconnect_by_func (context->channel,
+ G_CALLBACK (on_channel_abort_context),
+ context);
+ g_object_unref (context->channel);
+ }
+ g_free (context);
+}
+
+/* CONTEXT API */
+
+/* Context getters */
+const TpChan *
+mcd_dispatcher_context_get_channel_object (McdDispatcherContext * ctx)
+{
+ TpChan *tp_chan;
+ g_return_val_if_fail (ctx, 0);
+ g_object_get (G_OBJECT (ctx->channel), "tp-channel", &tp_chan, NULL);
+ g_object_unref (G_OBJECT (tp_chan));
+ return tp_chan;
+}
+
+McdDispatcher*
+mcd_dispatcher_context_get_dispatcher (McdDispatcherContext * ctx)
+{
+ return ctx->dispatcher;
+}
+
+const McdConnection *
+mcd_dispatcher_context_get_connection (McdDispatcherContext * context)
+{
+ McdConnection *connection;
+
+ g_return_val_if_fail (context, NULL);
+
+ g_object_get (G_OBJECT (context->channel),
+ "connection", &connection,
+ NULL);
+ g_object_unref (G_OBJECT (connection));
+
+ return connection;
+}
+
+const TpConn *
+mcd_dispatcher_context_get_connection_object (McdDispatcherContext * ctx)
+{
+ const McdConnection *connection;
+ TpConn *tp_conn;
+
+ connection = mcd_dispatcher_context_get_connection (ctx);
+ g_object_get (G_OBJECT (connection), "tp-connection",
+ &tp_conn, NULL);
+
+ g_object_unref (tp_conn);
+ return tp_conn;
+}
+
+McdChannel *
+mcd_dispatcher_context_get_channel (McdDispatcherContext * ctx)
+{
+ g_return_val_if_fail (ctx, 0);
+ return ctx->channel;
+}
+
+gpointer
+mcd_dispatcher_context_get_data (McdDispatcherContext * ctx)
+{
+ g_return_val_if_fail (ctx, NULL);
+ return ctx->data;
+}
+
+McdChannelHandler *
+mcd_dispatcher_context_get_chan_handler (McdDispatcherContext * ctx)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (ctx->dispatcher);
+ McdChannel *channel;
+
+ channel = mcd_dispatcher_context_get_channel (ctx);
+ return g_hash_table_lookup (priv->channel_handler_hash,
+ mcd_channel_get_channel_type (channel));
+}
+
+/*Returns an array of the participants in the channel*/
+GPtrArray *
+mcd_dispatcher_context_get_members (McdDispatcherContext * ctx)
+{
+ return mcd_channel_get_members (ctx->channel);
+}
+
+/* Context setters */
+void
+mcd_dispatcher_context_set_abort_fn (McdDispatcherContext * ctx, abort_function_t abort_fn)
+{
+ g_return_if_fail (ctx);
+ ctx->abort_fn = abort_fn;
+}
+
+void
+mcd_dispatcher_context_set_data (McdDispatcherContext * ctx, gpointer data)
+{
+ g_return_if_fail (ctx);
+ ctx->data = data;
+}
+
+GPtrArray *mcd_dispatcher_get_channel_capabilities (McdDispatcher * dispatcher)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (dispatcher);
+
+ return priv->channel_handler_caps;
+}
diff --git a/src/mcd-dispatcher.h b/src/mcd-dispatcher.h
new file mode 100644
index 00000000..6410adcf
--- /dev/null
+++ b/src/mcd-dispatcher.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_DISPATCHER_H
+#define MCD_DISPATCHER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-profile.h>
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-conn.h>
+
+G_BEGIN_DECLS
+
+#define MCD_TYPE_DISPATCHER (mcd_dispatcher_get_type ())
+#define MCD_DISPATCHER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_DISPATCHER, McdDispatcher))
+#define MCD_DISPATCHER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_DISPATCHER, McdDispatcherClass))
+#define MCD_IS_DISPATCHER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_DISPATCHER))
+#define MCD_IS_DISPATCHER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_DISPATCHER))
+#define MCD_DISPATCHER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_DISPATCHER, McdDispatcherClass))
+
+typedef struct _McdDispatcher McdDispatcher;
+typedef struct _McdDispatcherClass McdDispatcherClass;
+typedef struct _McdDispatcherStatus McdDispatcherStatus;
+
+#include "mcd-channel.h"
+#include "mcd-master.h"
+
+struct _McdDispatcher
+{
+ McdMission parent;
+};
+
+struct _McdDispatcherClass
+{
+ McdMissionClass parent_class;
+
+ /* signals */
+ void (*channel_added_signal) (McdDispatcher *dispatcher,
+ McdChannel *channel);
+ void (*channel_removed_signal) (McdDispatcher *dispatcher,
+ McdChannel *channel);
+ void (*dispatched_signal) (McdDispatcher * dispatcher,
+ McdChannel * channel);
+ void (*dispatch_failed_signal) (McdDispatcher * dispatcher,
+ McdChannel * channel,
+ GError *error);
+
+ /* virtual methods */
+ void (*send) (McdDispatcher * dispatcher, McdChannel *channel);
+};
+
+GType mcd_dispatcher_get_type (void);
+
+McdDispatcher *mcd_dispatcher_new (DBusGConnection * dbus_connection,
+ McdMaster * master);
+
+gboolean mcd_dispatcher_send (McdDispatcher * dispatcher, McdChannel *channel);
+
+McdDispatcherStatus
+mcd_dispatcher_get_status (McdDispatcher * dispatcher, McdChannel *channel);
+
+gint mcd_dispatcher_get_channel_type_usage (McdDispatcher * dispatcher,
+ GQuark chan_type_quark);
+
+/* retrieves the channel handlers' capabilities, in a format suitable for being
+ * used as a parameter for the telepathy "AdvertiseCapabilities" method */
+GPtrArray *mcd_dispatcher_get_channel_capabilities (McdDispatcher * dispatcher);
+
+G_END_DECLS
+
+#endif /* MCD_DISPATCHER_H */
diff --git a/src/mcd-filtering-int.h b/src/mcd-filtering-int.h
new file mode 100644
index 00000000..d5436e38
--- /dev/null
+++ b/src/mcd-filtering-int.h
@@ -0,0 +1,17 @@
+#ifndef _MCD_FILTERS_INT_H
+#define _MCD_FILTERS_INT_H
+
+#include "mcd-filtering.h"
+
+/* Internals of the filter-processing mechanism */
+
+void dispose_state_machine_data (mcdf_context_t sm_ctx);
+void start_channel_handler (mcdf_context_t ctx);
+void dispose_channel_request (ChanHandlerReq * request);
+void drop_channel_handler (mcdf_context_t ctx);
+void enter_state_machine (guint request_id, ChanHandlerReq * chan_req);
+
+
+
+
+#endif
diff --git a/src/mcd-main.c b/src/mcd-main.c
new file mode 100644
index 00000000..ac42d32e
--- /dev/null
+++ b/src/mcd-main.c
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include "mcd-service.h"
+
+int
+main (int argc, char **argv)
+{
+ McdService *mcd;
+
+ g_type_init ();
+
+ mcd = mcd_service_new ();
+
+ mcd_service_run (MCD_OBJECT (mcd));
+
+ return 0;
+}
diff --git a/src/mcd-manager.c b/src/mcd-manager.c
new file mode 100644
index 00000000..7121f881
--- /dev/null
+++ b/src/mcd-manager.c
@@ -0,0 +1,1065 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libtelepathy/tp-connmgr.h>
+#include <libtelepathy/tp-interfaces.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include "mcd-connection.h"
+#include "mcd-manager.h"
+
+#define MCD_MANAGER_PRIV(manager) (G_TYPE_INSTANCE_GET_PRIVATE ((manager), \
+ MCD_TYPE_MANAGER, \
+ McdManagerPrivate))
+
+G_DEFINE_TYPE (McdManager, mcd_manager, MCD_TYPE_OPERATION);
+
+typedef struct _McdManagerPrivate
+{
+ DBusGConnection *dbus_connection;
+ McManager *mc_manager;
+ McdPresenceFrame *presence_frame;
+ McdDispatcher *dispatcher;
+ TpConnMgr *tp_conn_mgr;
+ GList *accounts;
+ gboolean is_disposed;
+ gboolean delay_presence_request;
+
+ /* Table of channels to create upon connection */
+ GHashTable *requested_channels;
+} McdManagerPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_PRESENCE_FRAME,
+ PROP_DISPATCHER,
+ PROP_MC_MANAGER,
+ PROP_DBUS_CONNECTION,
+ PROP_ACCOUNTS
+};
+
+enum _McdManagerSignalType
+{
+ ACCOUNT_ADDED,
+ ACCOUNT_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint mcd_manager_signals[LAST_SIGNAL] = { 0 };
+
+static void abort_requested_channel (gchar *key,
+ struct mcd_channel_request *req,
+ McdManager *manager);
+
+static void
+_mcd_manager_create_connection (McdManager * manager, McAccount * account)
+{
+ McdConnection *connection;
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+
+ g_return_if_fail (mcd_manager_get_account_connection (manager, account) == NULL);
+
+ connection = mcd_connection_new (priv->dbus_connection,
+ mc_manager_get_bus_name (priv->
+ mc_manager),
+ priv->tp_conn_mgr, account,
+ priv->presence_frame,
+ priv->dispatcher);
+ mcd_operation_take_mission (MCD_OPERATION (manager),
+ MCD_MISSION (connection));
+ g_debug ("%s: Created a connection %p for account: %s", G_STRFUNC,
+ connection, mc_account_get_unique_name (account));
+}
+
+void
+_mcd_manager_create_connections (McdManager * manager)
+{
+ GList *node;
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+
+ g_return_if_fail (TELEPATHY_IS_CONNMGR (priv->tp_conn_mgr));
+
+ for (node = priv->accounts; node; node = node->next)
+ {
+ /* Create a connection object for each account */
+ McAccount *account = MC_ACCOUNT (node->data);
+
+ /* Only create a new connection if there already is not one */
+ if (!mcd_manager_get_account_connection (manager, account))
+ {
+ _mcd_manager_create_connection (manager, account);
+ }
+ }
+}
+
+static gint
+_find_connection (gconstpointer data, gconstpointer user_data)
+{
+ McdConnection *connection = MCD_CONNECTION (data);
+ McAccount *account = MC_ACCOUNT (user_data);
+ McAccount *connection_account = NULL;
+ gint ret;
+
+ g_object_get (G_OBJECT (connection), "account", &connection_account, NULL);
+
+ if (connection_account == account)
+ {
+ ret = 0;
+ }
+ else
+ {
+ ret = 1;
+ }
+
+ g_object_unref (G_OBJECT (connection_account));
+ return ret;
+}
+
+static gint
+_find_connection_by_path (gconstpointer data, gconstpointer user_data)
+{
+ TpConn *tp_conn;
+ McdConnection *connection = MCD_CONNECTION (data);
+ const gchar *object_path = (const gchar *)user_data;
+ const gchar *conn_object_path = NULL;
+ gint ret;
+
+ g_object_get (G_OBJECT (connection), "tp-connection",
+ &tp_conn, NULL);
+ if (!tp_conn)
+ return 1;
+ conn_object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (tp_conn));
+ if (strcmp (conn_object_path, object_path) == 0)
+ {
+ ret = 0;
+ }
+ else
+ {
+ ret = 1;
+ }
+
+ g_object_unref (G_OBJECT (tp_conn));
+ return ret;
+}
+
+static void
+requested_channel_process (gchar *key, struct mcd_channel_request *req,
+ McdManager *manager)
+{
+ GError *error = NULL;
+
+ g_debug ("%s: creating channel %s - %s - %s", G_STRFUNC, req->account_name, req->channel_type, req->channel_handle_string);
+
+ if (!mcd_manager_request_channel (manager, req, &error))
+ {
+ g_assert (error != NULL);
+ g_debug ("%s: channel request failed (%s)", G_STRFUNC, error->message);
+ g_error_free (error);
+ return;
+ }
+ g_assert (error == NULL);
+}
+
+static void
+on_presence_stable (McdPresenceFrame *presence_frame,
+ gboolean is_stable, McdManager *manager)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+
+ g_debug ("%s called", G_STRFUNC);
+ if (priv->requested_channels)
+ {
+ /* don't do anything until the presence frame is stable */
+ g_debug ("presence frame is %sstable", mcd_presence_frame_is_stable (presence_frame) ? "" : "not ");
+ if (!is_stable)
+ return;
+ if (mcd_presence_frame_get_actual_presence (presence_frame) >=
+ MC_PRESENCE_AVAILABLE)
+ {
+ g_hash_table_foreach (priv->requested_channels,
+ (GHFunc)requested_channel_process,
+ manager);
+ }
+ else
+ {
+ /* We couldn't connect; signal an error to the channel requestors
+ */
+ g_hash_table_foreach (priv->requested_channels,
+ (GHFunc)abort_requested_channel,
+ manager);
+ }
+ g_hash_table_destroy (priv->requested_channels);
+ priv->requested_channels = NULL;
+ }
+}
+
+static gboolean
+on_presence_requested_idle (gpointer data)
+{
+ McdManager *manager = MCD_MANAGER (data);
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+ McPresence requested_presence =
+ mcd_presence_frame_get_requested_presence (priv->presence_frame);
+ McPresence actual_presence =
+ mcd_presence_frame_get_actual_presence (priv->presence_frame);
+
+ g_debug ("%s: %d, %d", G_STRFUNC, requested_presence,
+ actual_presence);
+ if ((actual_presence == MC_PRESENCE_OFFLINE
+ || actual_presence == MC_PRESENCE_UNSET)
+ && (requested_presence != MC_PRESENCE_OFFLINE
+ && requested_presence != MC_PRESENCE_UNSET))
+ {
+ if (!priv->tp_conn_mgr)
+ {
+ g_return_val_if_fail (MC_IS_MANAGER (priv->mc_manager),
+ FALSE);
+
+ priv->tp_conn_mgr =
+ tp_connmgr_new (priv->dbus_connection,
+ mc_manager_get_bus_name (priv->
+ mc_manager),
+ mc_manager_get_object_path (priv->
+ mc_manager),
+ TP_IFACE_CONN_MGR_INTERFACE);
+ g_debug ("%s: Manager %s created", G_STRFUNC,
+ mc_manager_get_unique_name (priv->mc_manager));
+ }
+
+ _mcd_manager_create_connections (manager);
+ }
+
+ return FALSE;
+}
+
+static void
+abort_requested_channel (gchar *key, struct mcd_channel_request *req,
+ McdManager *manager)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+ McdChannel *channel;
+ GError *error;
+
+ g_debug ("%s: aborting channel %s - %s - %s", G_STRFUNC,
+ req->account_name, req->channel_type, req->channel_handle_string);
+ error = g_error_new (MC_ERROR, MC_NETWORK_ERROR,
+ "Connection cancelled");
+ /* we must create a channel object, just for delivering the error */
+ channel = mcd_channel_new (NULL,
+ NULL,
+ req->channel_type,
+ 0,
+ req->channel_handle_type,
+ TRUE, /* outgoing */
+ req->requestor_serial,
+ req->requestor_client_id);
+ g_signal_emit_by_name (priv->dispatcher, "dispatch-failed",
+ channel, error);
+ g_error_free (error);
+ /* this will actually destroy the channel object */
+ g_object_unref (channel);
+}
+
+static void
+abort_requested_channels (McdManager *manager)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+
+ g_debug ("%s called %p", G_STRFUNC, priv->requested_channels);
+ g_hash_table_foreach (priv->requested_channels,
+ (GHFunc)abort_requested_channel,
+ manager);
+ g_hash_table_destroy (priv->requested_channels);
+ priv->requested_channels = NULL;
+}
+
+static void
+on_presence_requested (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ const gchar * presence_message, gpointer data)
+{
+ McdManagerPrivate *priv;
+
+ g_debug ("%s: Current connectivity status is %d", G_STRFUNC,
+ mcd_mission_is_connected (MCD_MISSION (data)));
+
+ if (mcd_mission_is_connected (MCD_MISSION (data)))
+ {
+ on_presence_requested_idle(data);
+ }
+ else
+ {
+ priv = MCD_MANAGER_PRIV(data);
+ g_debug ("%s: Delaying call to on_presence_requested_idle", G_STRFUNC);
+ priv->delay_presence_request = TRUE;
+
+ /* if we are offline and the user cancels the connection request, we
+ * must clean the requested channels and return an error to the UI for
+ * each of them. */
+ if (presence == MC_PRESENCE_OFFLINE && priv->requested_channels != NULL)
+ abort_requested_channels (MCD_MANAGER (data));
+ }
+}
+
+/* FIXME: Until we have a proper serialization and deserialization, we will
+ * stick with killing all connections that were present before
+ * mission-control got control of telepathy managers
+ */
+/* Search the bus for already connected accounts and disconnect them. */
+static void
+_mcd_manager_nuke_connections (McdManager *manager)
+{
+ McdManagerPrivate *priv;
+ char **names, **name;
+ DBusGProxy *proxy;
+ GError *error = NULL;
+ static gboolean already_nuked = FALSE;
+
+ if (already_nuked)
+ return; /* We only nuke it once in process instance */
+ already_nuked = TRUE;
+
+ g_debug ("Nuking possible stale connections");
+
+ priv = MCD_MANAGER_PRIV (manager);
+ proxy = dbus_g_proxy_new_for_name(priv->dbus_connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ if (!proxy)
+ {
+ g_warning ("Error creating proxy");
+ return;
+ }
+
+ if (!dbus_g_proxy_call(proxy, "ListNames", &error, G_TYPE_INVALID,
+ G_TYPE_STRV, &names, G_TYPE_INVALID))
+ {
+ g_warning ("ListNames() failed: %s", error->message);
+ g_error_free (error);
+ g_object_unref (proxy);
+ return;
+ }
+
+ g_object_unref(proxy);
+
+ for (name = names; *name; name++)
+ {
+ if (strncmp(*name, "org.freedesktop.Telepathy.Connection.",
+ strlen("org.freedesktop.Telepathy.Connection.")) == 0)
+ {
+ gchar *path = g_strdelimit(g_strdup_printf("/%s", *name), ".", '/');
+
+ g_debug ("Trying to disconnect (%s), path=%s", *name, path);
+
+ proxy = dbus_g_proxy_new_for_name(priv->dbus_connection,
+ *name, path,
+ TP_IFACE_CONN_INTERFACE);
+
+ g_free(path);
+
+ if (proxy)
+ {
+ if (!dbus_g_proxy_call(proxy, "Disconnect", &error,
+ G_TYPE_INVALID, G_TYPE_INVALID))
+ {
+ g_warning ("Disconnect() failed: %s", error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+
+ g_object_unref(proxy);
+ }
+ else
+ {
+ g_warning ("Error creating proxy");
+ }
+ }
+ }
+ g_strfreev(names);
+}
+
+static void
+requested_channel_free (struct mcd_channel_request *req)
+{
+ g_free ((gchar *)req->account_name);
+ g_free ((gchar *)req->channel_type);
+ g_free ((gchar *)req->channel_handle_string);
+ g_free ((gchar *)req->requestor_client_id);
+ g_free (req);
+}
+
+static void
+request_channel_delayed (McdManager *manager,
+ const struct mcd_channel_request *req)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+ struct mcd_channel_request *req_cp;
+ gchar *key;
+
+ g_debug ("%s: account %s, type %s, handle %s", G_STRFUNC, req->account_name, req->channel_type, req->channel_handle_string);
+ if (!priv->requested_channels)
+ priv->requested_channels =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify)
+ requested_channel_free);
+
+ if (req->channel_handle_string)
+ key = g_strdup_printf("%s\n%s\n%s", req->account_name, req->channel_type,
+ req->channel_handle_string);
+ else
+ key = g_strdup_printf("%s\n%s\n%u", req->account_name, req->channel_type,
+ req->channel_handle);
+ req_cp = g_malloc (sizeof (struct mcd_channel_request));
+ memcpy(req_cp, req, sizeof (struct mcd_channel_request));
+ req_cp->account_name = g_strdup (req->account_name);
+ req_cp->channel_type = g_strdup (req->channel_type);
+ req_cp->channel_handle_string = g_strdup (req->channel_handle_string);
+ req_cp->requestor_client_id = g_strdup (req->requestor_client_id);
+ g_hash_table_insert (priv->requested_channels, key, req_cp);
+ g_free (key);
+}
+
+static void
+_mcd_manager_set_presence_frame (McdManager *manager, McdPresenceFrame *presence_frame)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+ if (presence_frame)
+ {
+ g_return_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame));
+ g_object_ref (presence_frame);
+ }
+
+ if (priv->presence_frame)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT
+ (priv->presence_frame),
+ G_CALLBACK
+ (on_presence_requested), manager);
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ G_CALLBACK
+ (on_presence_stable),
+ manager);
+ g_object_unref (priv->presence_frame);
+ }
+ priv->presence_frame = presence_frame;
+ if (priv->presence_frame)
+ {
+ g_signal_connect (G_OBJECT (priv->presence_frame),
+ "presence-requested",
+ G_CALLBACK (on_presence_requested), manager);
+ g_signal_connect (priv->presence_frame, "presence-stable",
+ G_CALLBACK (on_presence_stable), manager);
+ }
+}
+
+static void
+_mcd_manager_finalize (GObject * object)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (object);
+
+ if (priv->requested_channels)
+ {
+ g_hash_table_destroy (priv->requested_channels);
+ priv->requested_channels = NULL;
+ }
+ G_OBJECT_CLASS (mcd_manager_parent_class)->finalize (object);
+}
+
+static void
+_mcd_manager_dispose (GObject * object)
+{
+ GList *node;
+ McdManagerPrivate *priv;
+ priv = MCD_MANAGER_PRIV (object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+
+ priv->is_disposed = TRUE;
+
+ if (priv->accounts)
+ {
+ for (node = priv->accounts; node; node = node->next)
+ g_object_unref (G_OBJECT (node->data));
+ g_list_free (priv->accounts);
+ priv->accounts = NULL;
+ }
+
+ if (priv->dispatcher)
+ {
+ g_object_unref (priv->dispatcher);
+ priv->dispatcher = NULL;
+ }
+
+ _mcd_manager_set_presence_frame (MCD_MANAGER (object), NULL);
+
+ if (priv->dbus_connection)
+ {
+ dbus_g_connection_unref (priv->dbus_connection);
+ priv->dbus_connection = NULL;
+ }
+
+ if (priv->mc_manager)
+ {
+ g_object_unref (priv->mc_manager);
+ priv->mc_manager = NULL;
+ }
+
+ if (priv->tp_conn_mgr)
+ {
+ g_object_unref (priv->tp_conn_mgr);
+ priv->tp_conn_mgr = NULL;
+ }
+
+ G_OBJECT_CLASS (mcd_manager_parent_class)->dispose (object);
+}
+
+static void
+_mcd_manager_connect (McdMission * mission)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (mission);
+
+ g_debug ("%s: delay_presence_request = %d", G_STRFUNC, priv->delay_presence_request);
+ if (priv->delay_presence_request)
+ {
+ priv->delay_presence_request = FALSE;
+ g_idle_add (on_presence_requested_idle, mission);
+ g_debug ("%s: Added idle func on_presence_requested_idle", G_STRFUNC);
+ }
+ MCD_MISSION_CLASS (mcd_manager_parent_class)->connect (mission);
+}
+
+static void
+_mcd_manager_disconnect (McdMission * mission)
+{
+ GList *connections;
+
+ g_debug ("%s(%p)", G_STRFUNC, mission);
+ MCD_MISSION_CLASS (mcd_manager_parent_class)->disconnect (mission);
+
+ /* We now call mcd_mission_abort() on all child connections; but since this
+ * could modify the list of the children, we cannot just use
+ * mcd_operation_foreach(). Instead, make a copy of the list and work on
+ * that. */
+ g_debug("manager tree before abort:");
+ mcd_debug_print_tree(mission);
+ connections = g_list_copy ((GList *)mcd_operation_get_missions
+ (MCD_OPERATION (mission)));
+ g_list_foreach (connections, (GFunc) mcd_mission_abort, NULL);
+ g_list_free (connections);
+ g_debug("manager tree after abort:");
+ mcd_debug_print_tree(mission);
+}
+
+static void
+_mcd_manager_set_property (GObject * obj, guint prop_id,
+ const GValue * val, GParamSpec * pspec)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (obj);
+ McdPresenceFrame *presence_frame;
+ McdDispatcher *dispatcher;
+ McManager *mc_manager;
+ DBusGConnection *dbus_connection;
+
+ switch (prop_id)
+ {
+ case PROP_PRESENCE_FRAME:
+ presence_frame = g_value_get_object (val);
+ _mcd_manager_set_presence_frame (MCD_MANAGER (obj), presence_frame);
+ break;
+ case PROP_DISPATCHER:
+ dispatcher = g_value_get_object (val);
+ if (dispatcher)
+ {
+ g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
+ g_object_ref (dispatcher);
+ }
+ if (priv->dispatcher)
+ {
+ g_object_unref (priv->dispatcher);
+ }
+ priv->dispatcher = dispatcher;
+ break;
+ case PROP_MC_MANAGER:
+ mc_manager = g_value_get_object (val);
+ g_return_if_fail (MC_IS_MANAGER (mc_manager));
+ g_object_ref (mc_manager);
+ if (priv->mc_manager)
+ g_object_unref (priv->mc_manager);
+ priv->mc_manager = mc_manager;
+ break;
+ case PROP_DBUS_CONNECTION:
+ dbus_connection = g_value_get_pointer (val);
+ dbus_g_connection_ref (dbus_connection);
+ if (priv->dbus_connection)
+ dbus_g_connection_unref (priv->dbus_connection);
+ priv->dbus_connection = dbus_connection;
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_manager_get_property (GObject * obj, guint prop_id,
+ GValue * val, GParamSpec * pspec)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_PRESENCE_FRAME:
+ g_value_set_object (val, priv->presence_frame);
+ break;
+ case PROP_DISPATCHER:
+ g_value_set_object (val, priv->dispatcher);
+ break;
+ case PROP_MC_MANAGER:
+ g_value_set_object (val, priv->mc_manager);
+ break;
+ case PROP_DBUS_CONNECTION:
+ g_value_set_pointer (val, priv->dbus_connection);
+ break;
+ case PROP_ACCOUNTS:
+ g_debug ("%s: accounts getting over-written", G_STRFUNC);
+ g_value_set_pointer (val, priv->accounts);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mcd_manager_class_init (McdManagerClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ McdMissionClass *mission_class = MCD_MISSION_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (McdManagerPrivate));
+
+ object_class->finalize = _mcd_manager_finalize;
+ object_class->dispose = _mcd_manager_dispose;
+ object_class->set_property = _mcd_manager_set_property;
+ object_class->get_property = _mcd_manager_get_property;
+
+ mission_class->connect = _mcd_manager_connect;
+ mission_class->disconnect = _mcd_manager_disconnect;
+
+ /* signals */
+ mcd_manager_signals[ACCOUNT_ADDED] =
+ g_signal_new ("account-added",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdManagerClass, account_added_signal),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
+ mcd_manager_signals[ACCOUNT_REMOVED] =
+ g_signal_new ("account-removed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdManagerClass, account_removed_signal),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+ /* Properties */
+ g_object_class_install_property (object_class,
+ PROP_PRESENCE_FRAME,
+ g_param_spec_object ("presence-frame",
+ _
+ ("Presence Frame Object"),
+ _
+ ("Presence frame Object used by connections to update presence"),
+ MCD_TYPE_PRESENCE_FRAME,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPATCHER,
+ g_param_spec_object ("dispatcher",
+ _
+ ("Dispatcher Object"),
+ _
+ ("Channel dispatcher object"),
+ MCD_TYPE_DISPATCHER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_MC_MANAGER,
+ g_param_spec_object ("mc-manager",
+ _
+ ("McManager Object"),
+ _
+ ("McManager Object which this manager uses"),
+ MC_TYPE_MANAGER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_DBUS_CONNECTION,
+ g_param_spec_pointer ("dbus-connection",
+ _("DBus Connection"),
+ _
+ ("DBus connection to use by us"),
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class, PROP_ACCOUNTS,
+ g_param_spec_pointer ("accounts",
+ _("Accounts"),
+ _
+ ("List of accounts associated with this manager"),
+ G_PARAM_READABLE));
+}
+
+static void
+mcd_manager_init (McdManager * manager)
+{
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+
+ priv->dbus_connection = NULL;
+}
+
+/* Public methods */
+
+McdManager *
+mcd_manager_new (McManager * mc_manager,
+ McdPresenceFrame * pframe,
+ McdDispatcher *dispatcher,
+ DBusGConnection * dbus_connection)
+{
+ McdManager *obj;
+ obj = MCD_MANAGER (g_object_new (MCD_TYPE_MANAGER,
+ "mc-manager", mc_manager,
+ "presence-frame", pframe,
+ "dispatcher", dispatcher,
+ "dbus-connection", dbus_connection, NULL));
+ _mcd_manager_nuke_connections (obj);
+ return obj;
+}
+
+gboolean
+mcd_manager_can_handle_account (McdManager * manager, McAccount *account)
+{
+ McdManagerPrivate *priv;
+ McProfile *profile;
+ McProtocol *protocol;
+ McManager *mc_manager;
+ gboolean ret;
+
+ g_return_val_if_fail (MCD_IS_MANAGER (manager), FALSE);
+ g_return_val_if_fail (account != NULL, FALSE);
+
+ priv = MCD_MANAGER_PRIV (manager);
+
+ profile = account ? mc_account_get_profile (account) : NULL;
+ protocol = profile ? mc_profile_get_protocol (profile) : NULL;
+ mc_manager = protocol ? mc_protocol_get_manager (protocol) : NULL;
+
+ if (priv->mc_manager == mc_manager)
+ {
+ ret = TRUE;
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ if (profile)
+ g_object_unref (profile);
+ if (protocol)
+ g_object_unref (protocol);
+ if (mc_manager)
+ g_object_unref (mc_manager);
+
+ return ret;
+}
+
+McAccount *
+mcd_manager_get_account_by_name (McdManager * manager,
+ const gchar * account_name)
+{
+ GList *node;
+ McdManagerPrivate *priv;
+
+ g_return_val_if_fail (MCD_IS_MANAGER (manager), FALSE);
+ g_return_val_if_fail (account_name != NULL, FALSE);
+
+ priv = MCD_MANAGER_PRIV (manager);
+
+ node = priv->accounts;
+ while (node)
+ {
+ if (strcmp (mc_account_get_unique_name (MC_ACCOUNT (node->data)),
+ account_name) == 0)
+ return MC_ACCOUNT (node->data);
+ node = node->next;
+ }
+ return NULL;
+}
+
+gboolean
+mcd_manager_add_account (McdManager * manager, McAccount * account)
+{
+ McdManagerPrivate *priv;
+ McdConnection *connection;
+ McPresence actual_presence;
+
+ g_return_val_if_fail (MCD_IS_MANAGER (manager), FALSE);
+ g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
+
+ priv = MCD_MANAGER_PRIV (manager);
+
+ /* Make sure this account can be handled by this manager */
+ g_return_val_if_fail (mcd_manager_can_handle_account (manager, account),
+ FALSE);
+
+ /* Check if the account is already added */
+ if (g_list_find (priv->accounts, account))
+ return FALSE;
+
+ g_object_ref (account);
+ g_debug ("%s: %u accounts in total", G_STRFUNC, g_list_length (priv->accounts));
+ g_debug ("%s: adding account %p", G_STRFUNC, account);
+ priv->accounts = g_list_prepend (priv->accounts, account);
+ g_debug ("%s: %u accounts in total", G_STRFUNC, g_list_length (priv->accounts));
+
+ actual_presence =
+ mcd_presence_frame_get_actual_presence (priv->presence_frame);
+
+ connection = mcd_manager_get_account_connection (manager, account);
+ if (!connection)
+ {
+ /* if presence is not offline or unset, we must create the
+ * connection for this new account */
+ if ((actual_presence != MC_PRESENCE_OFFLINE &&
+ actual_presence != MC_PRESENCE_UNSET))
+ {
+ /* Also create the telepathy connection manager if not already
+ * created */
+ if (!priv->tp_conn_mgr)
+ {
+ g_return_val_if_fail (MC_IS_MANAGER (priv->mc_manager),
+ FALSE);
+
+ priv->tp_conn_mgr =
+ tp_connmgr_new (priv->dbus_connection,
+ mc_manager_get_bus_name (priv->
+ mc_manager),
+ mc_manager_get_object_path (priv->
+ mc_manager),
+ TP_IFACE_CONN_MGR_INTERFACE);
+ g_debug ("%s: Manager %s created", G_STRFUNC,
+ mc_manager_get_unique_name (priv->mc_manager));
+ }
+
+ _mcd_manager_create_connection (manager, account);
+ }
+ }
+
+ g_signal_emit_by_name (manager, "account-added", account);
+ return TRUE;
+}
+
+gboolean
+mcd_manager_remove_account (McdManager * manager, McAccount * account)
+{
+ McdManagerPrivate *priv;
+ McdConnection *connection;
+
+ g_return_val_if_fail (MCD_IS_MANAGER (manager), FALSE);
+ g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
+
+ priv = MCD_MANAGER_PRIV (manager);
+
+ if (!g_list_find (priv->accounts, account))
+ return FALSE;
+
+ connection = mcd_manager_get_account_connection (manager, account);
+ if (connection != NULL)
+ {
+ mcd_connection_close (connection);
+ }
+
+ g_debug ("%s: %u accounts in total", G_STRFUNC, g_list_length (priv->accounts));
+ g_debug ("%s: removing account %p", G_STRFUNC, account);
+ priv->accounts = g_list_remove (priv->accounts, account);
+ g_debug ("%s: %u accounts in total", G_STRFUNC, g_list_length (priv->accounts));
+ g_signal_emit_by_name (manager, "account-removed", account);
+
+ /* Account is unrefed after signal emission to prevent it being dead
+ * when the signal was emitted.
+ */
+ g_object_unref (account);
+
+ if (priv->accounts == NULL)
+ {
+ /* If we don't have any accounts, we don't have the right to live
+ * anymore. */
+ g_debug ("%s: commiting suicide", G_STRFUNC);
+ mcd_mission_abort (MCD_MISSION (manager));
+ }
+
+ return TRUE;
+}
+
+const GList *
+mcd_manager_get_accounts (McdManager * manager)
+{
+ return MCD_MANAGER_PRIV (manager)->accounts;
+}
+
+McdConnection *
+mcd_manager_get_account_connection (McdManager * manager,
+ McAccount * account)
+{
+ const GList *connections;
+ const GList *node;
+
+ connections = mcd_operation_get_missions (MCD_OPERATION (manager));
+ node = g_list_find_custom ((GList*)connections, account, _find_connection);
+
+ if (node != NULL)
+ {
+ return MCD_CONNECTION (node->data);
+ }
+
+ else
+ {
+ return NULL;
+ }
+}
+
+McdConnection *
+mcd_manager_get_connection (McdManager * manager, const gchar *object_path)
+{
+ const GList *connections;
+ const GList *node;
+
+ connections = mcd_operation_get_missions (MCD_OPERATION (manager));
+ node = g_list_find_custom ((GList*)connections, object_path,
+ _find_connection_by_path);
+
+ if (node != NULL)
+ {
+ return MCD_CONNECTION (node->data);
+ }
+
+ else
+ {
+ return NULL;
+ }
+}
+
+gboolean
+mcd_manager_request_channel (McdManager *manager,
+ const struct mcd_channel_request *req,
+ GError ** error)
+{
+ McAccount *account;
+ McdConnection *connection;
+
+ account = mcd_manager_get_account_by_name (manager, req->account_name);
+ if (!account)
+ {
+ /* ERROR here */
+ if (error)
+ {
+ g_set_error (error, MC_ERROR, MC_NO_MATCHING_CONNECTION_ERROR,
+ "No matching account found for account name '%s'",
+ req->account_name);
+ g_warning ("No matching account found for account name '%s'",
+ req->account_name);
+ }
+ return FALSE;
+ }
+
+ connection = mcd_manager_get_account_connection (manager, account);
+ if (!connection)
+ {
+ McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
+
+ g_debug ("%s: mcd-manager has connectivity status = %d", G_STRFUNC, mcd_mission_is_connected (MCD_MISSION (manager)));
+ if (!mcd_mission_is_connected (MCD_MISSION (manager)) ||
+ (mcd_presence_frame_get_actual_presence (priv->presence_frame) <= MC_PRESENCE_AVAILABLE &&
+ !mcd_presence_frame_is_stable (priv->presence_frame))
+ )
+ {
+ request_channel_delayed (manager, req);
+ return TRUE;
+ }
+ /* ERROR here */
+ if (error)
+ {
+ g_set_error (error, MC_ERROR, MC_NO_MATCHING_CONNECTION_ERROR,
+ "No matching connection found for account name '%s'",
+ req->account_name);
+ g_warning ("%s: No matching connection found for account name '%s'",
+ G_STRFUNC, req->account_name);
+ }
+ return FALSE;
+ }
+ else if (mcd_connection_get_connection_status (connection) !=
+ TP_CONN_STATUS_CONNECTED)
+ {
+ g_debug ("%s: connection is not connected", G_STRFUNC);
+ request_channel_delayed (manager, req);
+ return TRUE;
+ }
+
+ if (!mcd_connection_request_channel (connection, req, error))
+ {
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+ g_assert (error == NULL || *error == NULL);
+ return TRUE;
+}
+
+gboolean
+mcd_manager_cancel_channel_request (McdManager *manager, guint operation_id,
+ const gchar *requestor_client_id,
+ GError **error)
+{
+ const GList *connections, *node;
+
+ connections = mcd_operation_get_missions (MCD_OPERATION (manager));
+ if (!connections) return FALSE;
+
+ for (node = connections; node; node = node->next)
+ {
+ if (mcd_connection_cancel_channel_request (MCD_CONNECTION (node->data),
+ operation_id,
+ requestor_client_id,
+ error))
+ return TRUE;
+ }
+ return FALSE;
+}
+
diff --git a/src/mcd-manager.h b/src/mcd-manager.h
new file mode 100644
index 00000000..342198e5
--- /dev/null
+++ b/src/mcd-manager.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_MANAGER_H
+#define MCD_MANAGER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-manager.h>
+
+#include "mcd-connection.h"
+#include "mcd-operation.h"
+#include "mcd-presence-frame.h"
+#include "mcd-dispatcher.h"
+
+G_BEGIN_DECLS
+
+#define MCD_TYPE_MANAGER (mcd_manager_get_type ())
+#define MCD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_MANAGER, McdManager))
+#define MCD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_MANAGER, McdManagerClass))
+#define MCD_IS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_MANAGER))
+#define MCD_IS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_MANAGER))
+#define MCD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_MANAGER, McdManagerClass))
+
+typedef struct _McdManager McdManager;
+typedef struct _McdManagerClass McdManagerClass;
+
+struct _McdManager
+{
+ McdOperation parent;
+};
+
+struct _McdManagerClass
+{
+ McdOperationClass parent_class;
+
+ /* signals */
+ void (*account_added_signal) (McdManager * manager, McAccount * account);
+ void (*account_removed_signal) (McdManager * manager,
+ McAccount * account);
+};
+
+GType mcd_manager_get_type (void);
+McdManager *mcd_manager_new (McManager * mc_manager,
+ McdPresenceFrame * pframe,
+ McdDispatcher *dispatcher,
+ DBusGConnection * dbus_connection);
+
+gboolean mcd_manager_add_account (McdManager * manager, McAccount * account);
+gboolean mcd_manager_can_handle_account (McdManager * manager,
+ McAccount *account);
+McAccount* mcd_manager_get_account_by_name (McdManager * manager,
+ const gchar * account_name);
+gboolean mcd_manager_remove_account (McdManager * manager,
+ McAccount * account);
+const GList *mcd_manager_get_accounts (McdManager * manager);
+McdConnection *mcd_manager_get_account_connection (McdManager * manager,
+ McAccount * account);
+gboolean mcd_manager_request_channel (McdManager *manager,
+ const struct mcd_channel_request *req,
+ GError ** error);
+
+gboolean mcd_manager_cancel_channel_request (McdManager *manager, guint operation_id,
+ const gchar *requestor_client_pid, GError **error);
+
+McdConnection *mcd_manager_get_connection (McdManager *manager,
+ const gchar *object_path);
+
+G_END_DECLS
+#endif /* MCD_MANAGER_H */
diff --git a/src/mcd-master.c b/src/mcd-master.c
new file mode 100644
index 00000000..8dfd618f
--- /dev/null
+++ b/src/mcd-master.c
@@ -0,0 +1,1150 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib/gi18n.h>
+#include <gconf/gconf-client.h>
+#include <libmissioncontrol/mc-manager.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-profile.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include "mcd-master.h"
+#include "mcd-presence-frame.h"
+#include "mcd-proxy.h"
+#include "mcd-manager.h"
+#include "mcd-dispatcher.h"
+
+#define MCD_MASTER_PRIV(master) (G_TYPE_INSTANCE_GET_PRIVATE ((master), \
+ MCD_TYPE_MASTER, \
+ McdMasterPrivate))
+
+/**
+ * McdMaster:
+ * This class implements actual mission-control. It keeps track of
+ * individual account presence and connection states in a McdPresenceFrame
+ * member object, which is available as a property.
+ *
+ * The McdPresenceFrame object could be easily utilized for
+ * any presence releated events and actions, either within this class or
+ * any other class subclassing it or using it.
+ *
+ * It is basically a container for all McdManager objects and
+ * takes care of their management. It also takes care of sleep and awake
+ * cycles (e.g. translates to auto away somewhere down the hierarchy).
+ *
+ * McdMaster is a subclass of McdConroller, which essentially means it
+ * is subject to all device control.
+ */
+G_DEFINE_TYPE (McdMaster, mcd_master, MCD_TYPE_CONTROLLER);
+
+typedef struct _McdMasterPrivate
+{
+ McdPresenceFrame *presence_frame;
+ McdDispatcher *dispatcher;
+ McdProxy *proxy;
+ McPresence awake_presence;
+ const gchar *awake_presence_message;
+ McPresence default_presence;
+
+ /* We create this for our member objects */
+ DBusGConnection *dbus_connection;
+
+ /* Monitor for account enabling/disabling events */
+ McAccountMonitor *account_monitor;
+
+ /* if this flag is set, presence should go offline when all conversations
+ * are closed */
+ gboolean offline_on_idle;
+ GHashTable *clients_needing_presence;
+
+ gboolean is_disposed;
+} McdMasterPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_PRESENCE_FRAME,
+ PROP_DBUS_CONNECTION,
+ PROP_DISPATCHER,
+ PROP_DEFAULT_PRESENCE,
+};
+
+static void
+_mcd_master_init_managers (McdMaster * master)
+{
+ GList *acct, *acct_head;
+ GHashTable *mc_managers;
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ /* FIXME: Should get only _supported_ protocols */
+ /* Only enabled accounts are read in */
+
+ mc_managers = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ /* Deal with all enabled accounts */
+ acct_head = mc_accounts_list_by_enabled (TRUE);
+
+ /* Let the presence frame know what accounts we have */
+ mcd_presence_frame_set_accounts (priv->presence_frame, acct_head);
+
+ for (acct = acct_head; acct; acct = g_list_next (acct))
+ {
+ McAccount *account;
+ McProfile *profile;
+ McProtocol *protocol;
+ McManager *mc_manager;
+
+ account = acct ? acct->data : NULL;
+ profile = account ? mc_account_get_profile (account) : NULL;
+ protocol = profile ? mc_profile_get_protocol (profile) : NULL;
+ mc_manager = protocol ? mc_protocol_get_manager (protocol) : NULL;
+
+ if (mc_manager)
+ {
+ McdManager *manager;
+ manager = g_hash_table_lookup (mc_managers, mc_manager);
+
+ if (!manager)
+ {
+ manager =
+ mcd_manager_new (mc_manager, priv->presence_frame,
+ priv->dispatcher, priv->dbus_connection);
+ g_hash_table_insert (mc_managers, mc_manager, manager);
+ mcd_operation_take_mission (MCD_OPERATION (master),
+ MCD_MISSION (manager));
+ }
+ mcd_manager_add_account (manager, account);
+
+ g_debug ("%s: Added account:\n\tName\t\"%s\"\n\tProfile\t\"%s\""
+ "\n\tProto\t\"%s\"\n\tManager\t\"%s\"",
+ G_STRFUNC,
+ mc_account_get_unique_name (account),
+ mc_profile_get_unique_name (profile),
+ mc_protocol_get_name (protocol),
+ mc_manager_get_unique_name (mc_manager));
+ }
+ else
+ {
+ g_warning ("%s: Cannot add account:\n\tName\t\"%s\"\n\tProfile\t"
+ "\"%s\"\n\tProto\t\"%s\"\n\tManager\t\"%s\"",
+ G_STRFUNC,
+ account ? mc_account_get_unique_name (account) :
+ "NONE",
+ profile ? mc_profile_get_unique_name (profile) :
+ "NONE",
+ protocol ? mc_protocol_get_name (protocol) : "NONE",
+ mc_manager ?
+ mc_manager_get_unique_name (mc_manager) : "NONE");
+ }
+
+ if (profile)
+ g_object_unref (profile);
+ if (protocol)
+ g_object_unref (protocol);
+ if (mc_manager)
+ g_object_unref (mc_manager);
+ /* if (account)
+ g_object_unref (account); */
+ } /*for */
+ g_list_free (acct_head);
+ g_hash_table_destroy (mc_managers);
+}
+
+static gint
+_manager_has_account (McdManager * manager, McAccount * account)
+{
+ const GList *accounts;
+ const GList *account_node;
+
+ accounts = mcd_manager_get_accounts (manager);
+ account_node = g_list_find ((GList *) accounts, account);
+
+ if (account_node)
+ {
+ return 0;
+ }
+
+ else
+ {
+ return 1;
+ }
+}
+
+static McdManager *
+_mcd_master_find_manager (McdMaster * master, McAccount * account)
+{
+ const GList *managers;
+ const GList *manager_node;
+
+ managers = mcd_operation_get_missions (MCD_OPERATION (master));
+ manager_node =
+ g_list_find_custom ((GList*)managers, account,
+ (GCompareFunc) _manager_has_account);
+
+ if (manager_node)
+ {
+ return MCD_MANAGER (manager_node->data);
+ }
+
+ else
+ {
+ return NULL;
+ }
+}
+
+static gint
+_is_manager_responsible (McdManager * manager, McAccount * account)
+{
+ gboolean can_handle =
+ mcd_manager_can_handle_account (manager, account);
+
+ if (can_handle)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+static McdManager *
+_mcd_master_find_potential_manager (McdMaster * master, McAccount * account)
+{
+ const GList *managers;
+ const GList *manager_node;
+
+ managers = mcd_operation_get_missions (MCD_OPERATION (master));
+ manager_node =
+ g_list_find_custom ((GList*)managers, account,
+ (GCompareFunc) _is_manager_responsible);
+
+ if (manager_node)
+ {
+ return MCD_MANAGER (manager_node->data);
+ }
+
+ else
+ {
+ return NULL;
+ }
+}
+
+/* Reads in account's settings if they aren't in the hash table
+ already and (re)connects the account. */
+static void
+_mcd_master_on_account_enabled (McAccountMonitor * monitor,
+ gchar * account_name, gpointer user_data)
+{
+ McdMaster *master = MCD_MASTER (user_data);
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ McdManager *manager;
+ McAccount *account;
+
+ g_debug ("Account %s enabled", account_name);
+
+ account = mc_account_lookup (account_name);
+ manager = _mcd_master_find_potential_manager (master, account);
+
+ if (manager == NULL)
+ {
+ McProfile *profile;
+ McProtocol *protocol;
+ McManager *mc_manager;
+
+ g_debug ("%s: manager not found, creating a new one", G_STRFUNC);
+ profile = account ? mc_account_get_profile (account) : NULL;
+ protocol = profile ? mc_profile_get_protocol (profile) : NULL;
+ mc_manager = protocol ? mc_protocol_get_manager (protocol) : NULL;
+
+ if (mc_manager)
+ {
+ manager =
+ mcd_manager_new (mc_manager, priv->presence_frame,
+ priv->dispatcher, priv->dbus_connection);
+ mcd_operation_take_mission (MCD_OPERATION (master),
+ MCD_MISSION (manager));
+ }
+ else
+ {
+ g_warning ("%s: Failed to get the manager for the account:"
+ "\n\tName\t\"%s\"\n\tProfile\t\"%s\"\n\tProto"
+ "\t\"%s\"\n\tManager\t\"%s\"",
+ G_STRFUNC,
+ account ? mc_account_get_unique_name (account) :
+ "NONE",
+ profile ? mc_profile_get_unique_name (profile) :
+ "NONE",
+ protocol ? mc_protocol_get_name (protocol) : "NONE",
+ mc_manager ?
+ mc_manager_get_unique_name (mc_manager) : "NONE");
+ }
+
+ if (profile)
+ g_object_unref (profile);
+ if (protocol)
+ g_object_unref (protocol);
+ if (mc_manager)
+ g_object_unref (mc_manager);
+ }
+
+ if (manager != NULL)
+ {
+ g_debug ("adding account to manager and presence_frame");
+ mcd_presence_frame_add_account (priv->presence_frame, account);
+ mcd_manager_add_account (manager, account);
+ }
+
+ if (account)
+ g_object_unref (account);
+}
+
+static void
+_mcd_master_on_account_disabled (McAccountMonitor * monitor,
+ gchar * account_name, gpointer user_data)
+{
+ McdMaster *master = MCD_MASTER (user_data);
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ McdManager *manager;
+ McAccount *account;
+
+ g_debug ("Account %s disabled", account_name);
+
+ account = mc_account_lookup (account_name);
+
+ manager = _mcd_master_find_manager (master, account);
+
+ if (manager != NULL)
+ {
+ g_debug ("removing account from manager");
+ mcd_manager_remove_account (manager, account);
+ }
+
+ g_debug ("%s: removing account %s from presence_frame %p",
+ G_STRFUNC,
+ mc_account_get_unique_name (account),
+ priv->presence_frame);
+ mcd_presence_frame_remove_account (priv->presence_frame, account);
+
+ if (account)
+ g_object_unref (account);
+}
+
+static void
+_mcd_master_on_account_changed (McAccountMonitor * monitor,
+ gchar * account_name, McdMaster *master)
+{
+ McdManager *manager;
+ McAccount *account;
+
+ g_debug ("Account %s changed", account_name);
+
+ account = mc_account_lookup (account_name);
+ if (!account) return;
+ manager = _mcd_master_find_manager (master, account);
+
+ if (manager)
+ {
+ McdConnection *connection;
+
+ connection = mcd_manager_get_account_connection (manager, account);
+ if (connection)
+ mcd_connection_account_changed (connection);
+ }
+
+ g_object_unref (account);
+}
+
+static void
+_mcd_master_init_account_monitoring (McdMaster * master)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ priv->account_monitor = mc_account_monitor_new ();
+ g_signal_connect (priv->account_monitor,
+ "account-enabled",
+ (GCallback) _mcd_master_on_account_enabled, master);
+ g_signal_connect (priv->account_monitor,
+ "account-disabled",
+ (GCallback) _mcd_master_on_account_disabled, master);
+ g_signal_connect (priv->account_monitor,
+ "account-changed",
+ (GCallback) _mcd_master_on_account_changed, master);
+}
+
+static void
+_mcd_master_dispose_account_monitoring (McdMaster * master)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ g_signal_handlers_disconnect_by_func (priv->account_monitor,
+ (GCallback) _mcd_master_on_account_enabled, master);
+ g_signal_handlers_disconnect_by_func (priv->account_monitor,
+ (GCallback) _mcd_master_on_account_disabled, master);
+ g_signal_handlers_disconnect_by_func (priv->account_monitor,
+ (GCallback) _mcd_master_on_account_changed, master);
+ g_object_unref (priv->account_monitor);
+ priv->account_monitor = NULL;
+}
+
+static gboolean
+exists_supporting_invisible (McdMasterPrivate *priv)
+{
+ McPresence *presences, *presence;
+ gboolean found = FALSE;
+
+ presences =
+ mc_account_monitor_get_supported_presences (priv->account_monitor);
+ for (presence = presences; *presence; presence++)
+ if (*presence == MC_PRESENCE_HIDDEN)
+ {
+ found = TRUE;
+ break;
+ }
+ g_free (presences);
+ return found;
+}
+
+static McPresence
+_get_default_presence (McdMasterPrivate *priv)
+{
+ McPresence presence = priv->default_presence;
+
+ if (presence == MC_PRESENCE_OFFLINE)
+ {
+ /* Map offline to hidden if supported */
+ presence = exists_supporting_invisible (priv)?
+ MC_PRESENCE_HIDDEN : MC_PRESENCE_AWAY;
+ }
+
+ else if ((presence == MC_PRESENCE_HIDDEN) &&
+ (exists_supporting_invisible (priv) == FALSE))
+ {
+ /* Default presence was set to hidden/invisible but none of the
+ * accounts support it. Therefore use MC_PRESENCE_AWAY. */
+ g_debug ("Default presence setting is hidden but none of the "
+ "accounts support it. Falling back to away.");
+ presence = MC_PRESENCE_AWAY;
+ }
+
+ return presence;
+}
+
+static DBusHandlerResult
+dbus_filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ gpointer data)
+{
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ McdMasterPrivate *priv = (McdMasterPrivate *)data;
+
+ if (dbus_message_is_signal (message,
+ "org.freedesktop.DBus",
+ "NameOwnerChanged")) {
+ const gchar *name = NULL;
+ const gchar *prev_owner = NULL;
+ const gchar *new_owner = NULL;
+ DBusError error = {0};
+
+ dbus_error_init (&error);
+
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING,
+ &name,
+ DBUS_TYPE_STRING,
+ &prev_owner,
+ DBUS_TYPE_STRING,
+ &new_owner,
+ DBUS_TYPE_INVALID)) {
+
+ g_debug ("%s: error: %s", G_STRFUNC, error.message);
+ dbus_error_free (&error);
+
+ return result;
+ }
+
+ if (name && prev_owner && prev_owner[0] != '\0')
+ {
+ if (g_hash_table_lookup (priv->clients_needing_presence, prev_owner))
+ {
+ g_debug ("Process %s which requested default presence is dead", prev_owner);
+ g_hash_table_remove (priv->clients_needing_presence, prev_owner);
+ if (g_hash_table_size (priv->clients_needing_presence) == 0 &&
+ priv->offline_on_idle)
+ {
+ mcd_presence_frame_request_presence (priv->presence_frame,
+ MC_PRESENCE_OFFLINE,
+ "No active processes");
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_mcd_master_connect (McdMission * mission)
+{
+ MCD_MISSION_CLASS (mcd_master_parent_class)->connect (mission);
+ /*if (mission->main_presence.presence_enum != MC_PRESENCE_OFFLINE)
+ * mcd_connect_all_accounts(mission); */
+
+}
+
+static void
+_mcd_master_disconnect (McdMission * mission)
+{
+ g_debug ("%s", G_STRFUNC);
+
+ MCD_MISSION_CLASS (mcd_master_parent_class)->disconnect (mission);
+}
+
+static void
+_mcd_master_finalize (GObject * object)
+{
+ McdMaster *master;
+ master = MCD_MASTER (object);
+ G_OBJECT_CLASS (mcd_master_parent_class)->finalize (object);
+}
+
+static void
+_mcd_master_get_property (GObject * obj, guint prop_id,
+ GValue * val, GParamSpec * pspec)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_PRESENCE_FRAME:
+ g_value_set_object (val, priv->presence_frame);
+ break;
+ case PROP_DISPATCHER:
+ g_value_set_object (val, priv->dispatcher);
+ break;
+ case PROP_DBUS_CONNECTION:
+ g_value_set_pointer (val, priv->dbus_connection);
+ break;
+ case PROP_DEFAULT_PRESENCE:
+ g_value_set_uint (val, priv->default_presence);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_master_set_property (GObject *obj, guint prop_id,
+ const GValue *val, GParamSpec *pspec)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_DEFAULT_PRESENCE:
+ priv->default_presence = g_value_get_uint (val);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_master_set_flags (McdMission * mission, McdSystemFlags flags)
+{
+ McdSystemFlags idle_flag_old, idle_flag_new;
+ McdMasterPrivate *priv;
+
+ g_return_if_fail (MCD_IS_MASTER (mission));
+ priv = MCD_MASTER_PRIV (MCD_MASTER (mission));
+
+ idle_flag_old = MCD_MISSION_GET_FLAGS_MASKED (mission, MCD_SYSTEM_IDLE);
+ idle_flag_new = flags & MCD_SYSTEM_IDLE;
+
+ if (idle_flag_old != idle_flag_new)
+ {
+ if (idle_flag_new)
+ {
+ /* Save the current presence first */
+ priv->awake_presence =
+ mcd_presence_frame_get_actual_presence (priv->presence_frame);
+ if (priv->awake_presence != MC_PRESENCE_AVAILABLE)
+ return;
+ priv->awake_presence_message =
+ mcd_presence_frame_get_actual_presence_message (priv->presence_frame);
+
+ mcd_presence_frame_request_presence (priv->presence_frame,
+ MC_PRESENCE_AWAY, NULL);
+ }
+ else
+ {
+ mcd_presence_frame_request_presence (priv->presence_frame,
+ priv->awake_presence,
+ priv->awake_presence_message);
+ }
+ }
+ MCD_MISSION_CLASS (mcd_master_parent_class)->set_flags (mission, flags);
+}
+
+static void
+_mcd_master_dispose (GObject * object)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+ priv->is_disposed = TRUE;
+
+ g_hash_table_destroy (priv->clients_needing_presence);
+
+ if (priv->dbus_connection)
+ {
+ dbus_connection_remove_filter (dbus_g_connection_get_connection
+ (priv->dbus_connection),
+ dbus_filter_func, priv);
+
+ /* Flush all outgoing DBUS messages and signals */
+ dbus_g_connection_flush (priv->dbus_connection);
+ dbus_g_connection_unref (priv->dbus_connection);
+ priv->dbus_connection = NULL;
+ }
+
+ /* Don't unref() the dispatcher and the presence-frame: they will be
+ * unref()ed by the McdProxy */
+ priv->dispatcher = NULL;
+ priv->presence_frame = NULL;
+ g_object_unref (priv->proxy);
+
+ if (priv->account_monitor)
+ _mcd_master_dispose_account_monitoring (MCD_MASTER (object));
+
+ G_OBJECT_CLASS (mcd_master_parent_class)->dispose (object);
+}
+
+static void
+mcd_master_class_init (McdMasterClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ McdMissionClass *mission_class = MCD_MISSION_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McdMasterPrivate));
+
+ object_class->finalize = _mcd_master_finalize;
+ object_class->get_property = _mcd_master_get_property;
+ object_class->set_property = _mcd_master_set_property;
+ object_class->dispose = _mcd_master_dispose;
+
+ mission_class->connect = _mcd_master_connect;
+ mission_class->disconnect = _mcd_master_disconnect;
+ mission_class->set_flags = _mcd_master_set_flags;
+
+ /* Properties */
+ g_object_class_install_property (object_class,
+ PROP_PRESENCE_FRAME,
+ g_param_spec_object ("presence-frame",
+ _("Presence Frame Object"),
+ _("Presence frame Object used by connections to update presence"),
+ MCD_TYPE_PRESENCE_FRAME,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_DISPATCHER,
+ g_param_spec_object ("dispatcher",
+ _("Dispatcher Object"),
+ _("Dispatcher Object used to dispatch channels"),
+ MCD_TYPE_DISPATCHER,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_DBUS_CONNECTION,
+ g_param_spec_pointer ("dbus-connection",
+ _("D-Bus Connection"),
+ _("Connection to the D-Bus"),
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class, PROP_DEFAULT_PRESENCE,
+ g_param_spec_uint ("default-presence",
+ _("Default presence"),
+ _("Default presence when connecting"),
+ 0,
+ LAST_MC_PRESENCE,
+ 0,
+ G_PARAM_READWRITE));
+}
+
+static void
+install_dbus_filter (McdMasterPrivate *priv)
+{
+ DBusConnection *dbus_conn;
+ DBusError error;
+
+ /* set up the NameOwnerChange filter */
+ dbus_conn = dbus_g_connection_get_connection (priv->dbus_connection);
+ dbus_error_init (&error);
+ dbus_connection_add_filter (dbus_conn,
+ dbus_filter_func,
+ priv, NULL);
+ dbus_bus_add_match (dbus_conn,
+ "type='signal'," "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged'", &error);
+ if (dbus_error_is_set (&error))
+ {
+ g_warning ("Match rule adding failed");
+ dbus_error_free (&error);
+ }
+}
+
+static void
+mcd_master_init (McdMaster * master)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ GError *error = NULL;
+ /* Initialize DBus connection */
+ priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_STARTER, &error);
+ if (priv->dbus_connection == NULL)
+ {
+ g_printerr ("Failed to open connection to bus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ install_dbus_filter (priv);
+
+ priv->presence_frame = mcd_presence_frame_new ();
+ priv->dispatcher = mcd_dispatcher_new (priv->dbus_connection, master);
+ g_assert (MCD_IS_DISPATCHER (priv->dispatcher));
+ /* propagate the signals to dispatcher and presence_frame, too */
+ priv->proxy = mcd_proxy_new (MCD_MISSION (master));
+ mcd_operation_take_mission (MCD_OPERATION (priv->proxy),
+ MCD_MISSION (priv->presence_frame));
+ mcd_operation_take_mission (MCD_OPERATION (priv->proxy),
+ MCD_MISSION (priv->dispatcher));
+
+ _mcd_master_init_managers (master);
+
+ /* Listen for account enable/disable events */
+ _mcd_master_init_account_monitoring (master);
+
+ priv->clients_needing_presence = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free, NULL);
+}
+
+McdMaster *
+mcd_master_new (void)
+{
+ McdMaster *obj;
+ obj = MCD_MASTER (g_object_new (MCD_TYPE_MASTER, NULL));
+ return obj;
+}
+
+static void
+mcd_master_set_offline_on_idle (McdMaster *master, gboolean offline_on_idle)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ g_debug ("%s: setting offline_on_idle to %d", G_STRFUNC, offline_on_idle);
+ priv->offline_on_idle = offline_on_idle;
+}
+
+void
+mcd_master_request_presence (McdMaster * master,
+ McPresence presence,
+ const gchar * presence_message)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ mcd_presence_frame_request_presence (priv->presence_frame, presence,
+ presence_message);
+ if (presence >= MC_PRESENCE_AVAILABLE)
+ mcd_master_set_offline_on_idle (master, FALSE);
+}
+
+McPresence
+mcd_master_get_actual_presence (McdMaster * master)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ return mcd_presence_frame_get_actual_presence (priv->presence_frame);
+}
+
+McPresence
+mcd_master_get_requested_presence (McdMaster * master)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ return mcd_presence_frame_get_requested_presence (priv->presence_frame);
+}
+
+gboolean
+mcd_master_set_default_presence (McdMaster * master, const gchar *client_id)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ McPresence presence;
+
+ presence = _get_default_presence (priv);
+ if (presence == MC_PRESENCE_UNSET)
+ return FALSE;
+
+ if (client_id)
+ {
+ if (g_hash_table_lookup (priv->clients_needing_presence, client_id) == NULL)
+ {
+ g_debug ("New process requesting default presence (%s)", client_id);
+ g_hash_table_insert (priv->clients_needing_presence,
+ g_strdup (client_id), GINT_TO_POINTER(1));
+ }
+ }
+
+ if (mcd_presence_frame_get_actual_presence (priv->presence_frame)
+ >= MC_PRESENCE_AVAILABLE ||
+ !mcd_presence_frame_is_stable (priv->presence_frame) ||
+ /* if we are not connected the presence frame will always be stable,
+ * but this doesn't mean we must accept this request; maybe another one
+ * is pending */
+ (!mcd_mission_is_connected (MCD_MISSION (master)) &&
+ mcd_presence_frame_get_requested_presence (priv->presence_frame)
+ >= MC_PRESENCE_AVAILABLE))
+ {
+ g_warning ("%s: Default presence requested while connected or "
+ "already connecting", G_STRFUNC);
+ return FALSE;
+ }
+ mcd_master_set_offline_on_idle (master, TRUE);
+ mcd_presence_frame_request_presence (priv->presence_frame, presence, NULL);
+ return TRUE;
+}
+
+TelepathyConnectionStatus
+mcd_master_get_account_status (McdMaster * master, gchar * account_name)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ TelepathyConnectionStatus status;
+ McAccount *account;
+
+ account = mc_account_lookup (account_name);
+ status = mcd_presence_frame_get_account_status (priv->presence_frame,
+ account);
+ g_object_unref (account);
+ return status;
+}
+
+gboolean
+mcd_master_get_online_connection_names (McdMaster * master,
+ gchar *** connected_names)
+{
+ GList *accounts;
+ gboolean ret;
+
+ accounts = mc_accounts_list_by_enabled (TRUE);
+
+ /* MC exits if there aren't any accounts */
+ if (accounts)
+ {
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ GPtrArray *names = g_ptr_array_new ();
+ GList *account_node;
+
+ /* Iterate through all connected accounts */
+ for (account_node = accounts; account_node;
+ account_node = g_list_next (account_node))
+ {
+ McAccount *account = account_node->data;
+ TelepathyConnectionStatus status;
+
+ status =
+ mcd_presence_frame_get_account_status (priv->presence_frame,
+ account);
+ /* Ensure that only accounts that are actually conntected are added to
+ * the pointer array. */
+
+ if (status == TP_CONN_STATUS_CONNECTED)
+ {
+ g_ptr_array_add (names,
+ g_strdup (mc_account_get_unique_name
+ (account)));
+ }
+ }
+
+ if (names->len != 0)
+ {
+ int i;
+
+ /* Copy the collected names to the array of strings */
+ *connected_names =
+ (gchar **) g_malloc0 (sizeof (gchar *) * (names->len + 1));
+ for (i = 0; i < names->len; i++)
+ {
+ *(*connected_names + i) = g_ptr_array_index (names, i);
+ }
+ (*connected_names)[i] = NULL;
+
+ ret = TRUE;
+ }
+
+ else
+ {
+ ret = FALSE;
+ }
+
+ g_ptr_array_free (names, TRUE);
+ g_list_free (accounts);
+ }
+
+ else
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+gboolean
+mcd_master_get_account_connection_details (McdMaster * master,
+ const gchar * account_name,
+ gchar ** servname, gchar ** objpath)
+{
+ McAccount *account;
+ McdManager *manager;
+ McdConnection *connection;
+ gboolean ret = FALSE;
+
+ account = mc_account_lookup (account_name);
+ if (account)
+ {
+ manager = _mcd_master_find_manager (master, account);
+ connection =
+ manager ? mcd_manager_get_account_connection (manager, account) : NULL;
+ g_object_unref (account);
+
+ if (connection)
+ ret =
+ mcd_connection_get_telepathy_details (connection, servname,
+ objpath);
+ }
+
+ return ret;
+}
+
+gboolean
+mcd_master_request_channel (McdMaster *master,
+ const struct mcd_channel_request *req,
+ GError ** error)
+{
+ const GList *managers, *node;
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ g_return_val_if_fail (MCD_IS_MASTER (master), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ /* Low memory ? */
+ if (MCD_MISSION_GET_FLAGS_MASKED (MCD_MISSION (master),
+ MCD_SYSTEM_MEMORY_CONSERVED))
+ {
+ g_warning ("Device is in lowmem state, will not create a channel");
+ if (error)
+ g_set_error (error, MC_ERROR, MC_LOWMEM_ERROR, "Low memory");
+ return FALSE;
+ }
+
+ /* First find out the right manager */
+ managers = mcd_operation_get_missions (MCD_OPERATION (master));
+
+ /* If there are no accounts, error */
+ if (managers == NULL)
+ {
+ if (error)
+ {
+ g_set_error (error, MC_ERROR, MC_NO_ACCOUNTS_ERROR,
+ "No accounts configured");
+ }
+ g_warning ("No accounts configured");
+
+ /* Nothing to do. Just exit */
+ mcd_controller_shutdown (MCD_CONTROLLER (master),
+ "No accounts configured");
+ return FALSE;
+ }
+
+ /* make sure we are online, or will be */
+ if (mcd_presence_frame_get_actual_presence (priv->presence_frame) <= MC_PRESENCE_AVAILABLE &&
+ mcd_presence_frame_is_stable (priv->presence_frame))
+ {
+ g_debug ("%s: requesting default presence", G_STRFUNC);
+ mcd_master_set_default_presence (master, NULL);
+ }
+
+ node = managers;
+ while (node)
+ {
+ if (mcd_manager_get_account_by_name (MCD_MANAGER (node->data),
+ req->account_name))
+ {
+ /* FIXME: handle error correctly */
+ if (!mcd_manager_request_channel (MCD_MANAGER (node->data),
+ req, error))
+ {
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+ g_assert (error == NULL || *error == NULL);
+ return TRUE;
+ }
+ node = node->next;
+ }
+
+ /* Manager not found */
+ if (error)
+ {
+ g_set_error (error, MC_ERROR, MC_NO_MATCHING_CONNECTION_ERROR,
+ "No matching manager found for account %s",
+ req->account_name);
+ }
+ g_warning ("No matching manager found for account %s", req->account_name);
+ return FALSE;
+}
+
+gboolean
+mcd_master_cancel_channel_request (McdMaster *master, guint operation_id,
+ const gchar *requestor_client_id,
+ GError **error)
+{
+ const GList *managers, *node;
+
+ g_return_val_if_fail (MCD_IS_MASTER (master), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ /* First find out the right manager */
+ managers = mcd_operation_get_missions (MCD_OPERATION (master));
+ if (!managers) return FALSE;
+
+ for (node = managers; node; node = node->next)
+ {
+ if (mcd_manager_cancel_channel_request (MCD_MANAGER (node->data),
+ operation_id,
+ requestor_client_id,
+ error))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+mcd_master_cancel_last_presence_request (McdMaster * master)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+
+ return mcd_presence_frame_cancel_last_request (priv->presence_frame);
+}
+
+gboolean
+mcd_master_get_used_channels_count (McdMaster *master, guint chan_type,
+ guint * ret, GError ** error)
+{
+ McdMasterPrivate *priv;
+
+ g_return_val_if_fail (ret != NULL, FALSE);
+
+ priv = MCD_MASTER_PRIV (master);
+ *ret = mcd_dispatcher_get_channel_type_usage (priv->dispatcher,
+ chan_type);
+ return TRUE;
+}
+
+McdConnection *
+mcd_master_get_connection (McdMaster *master, const gchar *object_path,
+ GError **error)
+{
+ McdConnection *connection;
+ const GList *managers, *node;
+
+ g_return_val_if_fail (MCD_IS_MASTER (master), NULL);
+
+ managers = mcd_operation_get_missions (MCD_OPERATION (master));
+
+ /* MC exits if there aren't any accounts */
+ if (managers == NULL)
+ {
+ if (error)
+ {
+ g_set_error (error, MC_ERROR, MC_NO_ACCOUNTS_ERROR,
+ "No accounts configured");
+ }
+ mcd_controller_shutdown (MCD_CONTROLLER (master),
+ "No accounts configured");
+ return NULL;
+ }
+
+ node = managers;
+ while (node)
+ {
+ connection = mcd_manager_get_connection (MCD_MANAGER (node->data),
+ object_path);
+ if (connection)
+ return connection;
+ node = node->next;
+ }
+
+ /* Manager not found */
+ if (error)
+ {
+ g_set_error (error, MC_ERROR, MC_NO_MATCHING_CONNECTION_ERROR,
+ "No matching manager found for connection '%s'",
+ object_path);
+ }
+ return NULL;
+}
+
+gboolean
+mcd_master_get_account_for_connection (McdMaster *master,
+ const gchar *object_path,
+ gchar **ret_unique_name,
+ GError **error)
+{
+ McdConnection *connection;
+
+ connection = mcd_master_get_connection (master, object_path, error);
+ if (connection)
+ {
+ McAccount *account;
+
+ g_object_get (G_OBJECT (connection), "account", &account, NULL);
+ *ret_unique_name = g_strdup (mc_account_get_unique_name (account));
+ g_object_unref (G_OBJECT (account));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+mcd_master_set_default_presence_setting (McdMaster *master,
+ McPresence presence)
+{
+ McdMasterPrivate *priv = MCD_MASTER_PRIV (master);
+ priv->default_presence = presence;
+}
+
diff --git a/src/mcd-master.h b/src/mcd-master.h
new file mode 100644
index 00000000..865da395
--- /dev/null
+++ b/src/mcd-master.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_MASTER_H
+#define MCD_MASTER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include "mcd-controller.h"
+
+G_BEGIN_DECLS
+#define MCD_TYPE_MASTER (mcd_master_get_type ())
+#define MCD_MASTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_MASTER, McdMaster))
+#define MCD_MASTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_MASTER, McdMasterClass))
+#define MCD_IS_MASTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_MASTER))
+#define MCD_IS_MASTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_MASTER))
+#define MCD_MASTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_MASTER, McdMasterClass))
+
+typedef struct _McdMaster McdMaster;
+typedef struct _McdMasterClass McdMasterClass;
+
+#include <mcd-connection.h>
+
+struct _McdMaster
+{
+ McdController parent;
+};
+
+struct _McdMasterClass
+{
+ McdControllerClass parent_class;
+};
+
+struct mcd_channel_request;
+
+GType mcd_master_get_type (void);
+McdMaster *mcd_master_new (void);
+void mcd_master_request_presence (McdMaster * master,
+ McPresence presence,
+ const gchar * presence_message);
+
+McPresence mcd_master_get_actual_presence (McdMaster * master);
+
+McPresence mcd_master_get_requested_presence (McdMaster * master);
+
+gboolean mcd_master_set_default_presence (McdMaster * master,
+ const gchar *client_id);
+
+void mcd_master_set_default_presence_setting (McdMaster *master,
+ McPresence presence);
+
+TelepathyConnectionStatus mcd_master_get_account_status (McdMaster * master,
+ gchar * account_name);
+
+gboolean mcd_master_get_online_connection_names (McdMaster * master,
+ gchar *** connected_names);
+
+gboolean mcd_master_get_account_connection_details (McdMaster * master,
+ const gchar * account_name,
+ gchar ** servname,
+ gchar ** objpath);
+
+gboolean mcd_master_cancel_last_presence_request (McdMaster * master);
+
+gboolean mcd_master_request_channel (McdMaster *master,
+ const struct mcd_channel_request *req,
+ GError ** error);
+
+gboolean mcd_master_cancel_channel_request (McdMaster *master,
+ guint operation_id,
+ const gchar *requestor_client_id,
+ GError **error);
+
+gboolean mcd_master_get_used_channels_count (McdMaster *master, guint chan_type,
+ guint * ret, GError ** error);
+McdConnection *mcd_master_get_connection (McdMaster *master,
+ const gchar *object_path,
+ GError **error);
+gboolean mcd_master_get_account_for_connection (McdMaster *master,
+ const gchar *object_path,
+ gchar **ret_unique_name,
+ GError **error);
+
+G_END_DECLS
+#endif /* MCD_MASTER_H */
diff --git a/src/mcd-mission.c b/src/mcd-mission.c
new file mode 100644
index 00000000..6b02f166
--- /dev/null
+++ b/src/mcd-mission.c
@@ -0,0 +1,482 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib/gi18n.h>
+#include "mcd-mission.h"
+#include "mcd-enum-types.h"
+
+#define MCD_MISSION_PRIV(mission) (G_TYPE_INSTANCE_GET_PRIVATE ((mission), \
+ MCD_TYPE_MISSION, \
+ McdMissionPrivate))
+
+/**
+ * McdMission:
+ * It is the base class for every object in mission-control. It defines
+ * a set of virtual functions and set of corresponding action signals.
+ * all virtual functions results in emission of their corresponding action
+ * signals. The virtual functions define states of the object, such
+ * as memory conserved state, connected state, locked state, low power state,
+ * lit state, sleeping state etc. Each of the object states can also be queried
+ * independently as properties.
+ *
+ * There are also some action signals such as abort, which is used to notify
+ * other objects holding hard references to it to release them (this object
+ * should then automatically die since all held references are released). It
+ * is mandatory for all other objects that hold a hard reference to it to
+ * listen for this signal and release the reference in signal handler.
+ *
+ * Concrete derived classes should override the sate methods to implement
+ * object specific state managements.
+ */
+G_DEFINE_TYPE (McdMission, mcd_mission, G_TYPE_OBJECT);
+
+/* Private */
+
+typedef struct _McdMissionPrivate
+{
+ McdMission *parent;
+ McdSystemFlags flags;
+ McdMode mode;
+
+ gboolean is_disposed;
+
+} McdMissionPrivate;
+
+enum _McdMissionSignalType
+{
+ CONNECTED,
+ DISCONNECTED,
+ FLAGS_CHANGED,
+ MODE_SET,
+ PARENT_SET,
+ ABORT,
+ LAST_SIGNAL
+};
+
+enum _McdMissionPropertyType
+{
+ PROP_0,
+ PROP_SYSTEM_FLAGS,
+ PROP_MODE,
+ PROP_PARENT
+};
+
+static guint mcd_mission_signals[LAST_SIGNAL] = { 0 };
+
+static void
+_mcd_mission_connect (McdMission * mission)
+{
+ McdMissionPrivate *priv;
+
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ priv = MCD_MISSION_PRIV (mission);
+
+ if (!mcd_mission_is_connected (mission))
+ {
+ gint flags = mcd_mission_get_flags (mission);
+ flags |= MCD_SYSTEM_CONNECTED;
+ mcd_mission_set_flags (mission, flags);
+ g_signal_emit_by_name (mission, "connected");
+ }
+}
+
+static void
+_mcd_mission_disconnect (McdMission * mission)
+{
+ McdMissionPrivate *priv;
+
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ priv = MCD_MISSION_PRIV (mission);
+
+ if (mcd_mission_is_connected (mission))
+ {
+ gint flags = mcd_mission_get_flags (mission);
+ flags &= ~MCD_SYSTEM_CONNECTED;
+ mcd_mission_set_flags (mission, flags);
+ g_signal_emit_by_name (mission, "disconnected");
+ }
+}
+
+static void
+_mcd_mission_set_flags (McdMission * mission, McdSystemFlags flags)
+{
+ McdMissionPrivate *priv;
+
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ priv = MCD_MISSION_PRIV (mission);
+
+ if (priv->flags != flags)
+ {
+ priv->flags = flags;
+ g_signal_emit_by_name (mission, "flags-changed", flags);
+ }
+}
+
+static McdSystemFlags
+_mcd_mission_get_flags (McdMission * mission)
+{
+ McdMissionPrivate *priv;
+
+ g_return_val_if_fail (MCD_IS_MISSION (mission), MCD_MODE_UNKNOWN);
+ priv = MCD_MISSION_PRIV (mission);
+
+ return priv->flags;
+}
+
+static void
+_mcd_mission_set_mode (McdMission * mission, McdMode mode)
+{
+ McdMissionPrivate *priv;
+
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ priv = MCD_MISSION_PRIV (mission);
+
+ if (priv->mode != mode)
+ {
+ priv->mode = mode;
+
+ g_signal_emit_by_name (mission, "mode-set", mode);
+ }
+}
+
+static McdMode
+_mcd_mission_get_mode (McdMission * mission)
+{
+ McdMissionPrivate *priv;
+
+ g_return_val_if_fail (MCD_IS_MISSION (mission), MCD_MODE_UNKNOWN);
+ priv = MCD_MISSION_PRIV (mission);
+
+ return priv->mode;
+}
+
+static void
+on_parent_abort (McdMission *parent, McdMission *mission)
+{
+ g_debug ("%s called", G_STRFUNC);
+ mcd_mission_set_parent (mission, NULL);
+}
+
+static void
+_mcd_mission_set_parent (McdMission * mission, McdMission * parent)
+{
+ McdMissionPrivate *priv;
+
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ g_return_if_fail ((parent == NULL) || MCD_IS_MISSION (parent));
+
+ priv = MCD_MISSION_PRIV (mission);
+
+ g_debug ("%s: child = %p, parent = %p", G_STRFUNC, mission, parent);
+
+ if (priv->parent)
+ {
+ g_signal_handlers_disconnect_by_func (priv->parent,
+ on_parent_abort,
+ mission);
+ }
+
+ if (parent)
+ {
+ g_signal_connect (parent, "abort",
+ G_CALLBACK (on_parent_abort),
+ mission);
+ g_object_ref (parent);
+ }
+
+ if (priv->parent)
+ {
+ g_object_unref (priv->parent);
+ }
+
+ priv->parent = parent;
+ g_signal_emit_by_name (mission, "parent-set", parent);
+}
+
+static void
+_mcd_mission_abort (McdMission * mission)
+{
+ g_signal_emit_by_name (G_OBJECT (mission), "abort");
+}
+
+static void
+_mcd_mission_dispose (GObject * object)
+{
+ McdMissionPrivate *priv;
+ g_return_if_fail (MCD_IS_MISSION (object));
+
+ priv = MCD_MISSION_PRIV (object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+
+ priv->is_disposed = TRUE;
+
+ g_debug ("mission disposed %p", object);
+ if (priv->parent)
+ {
+ g_signal_handlers_disconnect_by_func (priv->parent,
+ on_parent_abort,
+ object);
+ g_object_unref (priv->parent);
+ priv->parent = NULL;
+ }
+ G_OBJECT_CLASS (mcd_mission_parent_class)->dispose (object);
+}
+
+static void
+_mcd_mission_finalize (GObject * object)
+{
+ g_debug ("mission finalized %p", object);
+ G_OBJECT_CLASS (mcd_mission_parent_class)->finalize (object);
+}
+
+static void
+_mcd_set_property (GObject * object, guint prop_id, const GValue * val,
+ GParamSpec * pspec)
+{
+ McdMission *mission = MCD_MISSION (object);
+
+ switch (prop_id)
+ {
+ case PROP_PARENT:
+ mcd_mission_set_parent (mission, g_value_get_object (val));
+ break;
+ case PROP_SYSTEM_FLAGS:
+ mcd_mission_set_flags (mission, g_value_get_enum (val));
+ break;
+ case PROP_MODE:
+ mcd_mission_set_mode (mission, g_value_get_int (val));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_get_property (GObject * object, guint prop_id, GValue * val,
+ GParamSpec * pspec)
+{
+ McdMission *mission = MCD_MISSION (object);
+
+ switch (prop_id)
+ {
+ case PROP_PARENT:
+ g_value_set_object (val, mcd_mission_get_parent (mission));
+ break;
+ case PROP_SYSTEM_FLAGS:
+ g_value_set_enum (val, mcd_mission_get_flags (mission));
+ break;
+ case PROP_MODE:
+ g_value_set_enum (val, mcd_mission_get_mode (mission));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mcd_mission_class_init (McdMissionClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (McdMissionPrivate));
+
+ /* virtual medthods */
+ object_class->finalize = _mcd_mission_finalize;
+ object_class->dispose = _mcd_mission_dispose;
+ object_class->set_property = _mcd_set_property;
+ object_class->get_property = _mcd_get_property;
+
+ /* virtual medthods */
+ klass->abort = _mcd_mission_abort;
+ klass->connect = _mcd_mission_connect;
+ klass->disconnect = _mcd_mission_disconnect;
+ klass->set_flags = _mcd_mission_set_flags;
+ klass->get_flags = _mcd_mission_get_flags;
+ klass->set_mode = _mcd_mission_set_mode;
+ klass->get_mode = _mcd_mission_get_mode;
+
+ klass->set_parent = _mcd_mission_set_parent;
+
+ /* signals */
+ mcd_mission_signals[ABORT] =
+ g_signal_new ("abort",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdMissionClass, abort_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+ 0);
+ mcd_mission_signals[CONNECTED] =
+ g_signal_new ("connected", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (McdMissionClass,
+ connected_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+ 0);
+ mcd_mission_signals[DISCONNECTED] =
+ g_signal_new ("disconnected", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (McdMissionClass,
+ disconnected_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+ 0);
+ mcd_mission_signals[FLAGS_CHANGED] =
+ g_signal_new ("flags-changed", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (McdMissionClass,
+ flags_changed_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE,
+ 1, MCD_TYPE_SYSTEM_FLAGS);
+ mcd_mission_signals[MODE_SET] =
+ g_signal_new ("mode-set", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (McdMissionClass,
+ mode_set_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE,
+ 1, MCD_TYPE_MODE);
+ mcd_mission_signals[PARENT_SET] =
+ g_signal_new ("parent-set", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (McdMissionClass,
+ parent_set_signal),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+ 0);
+
+ /* Properties */
+ g_object_class_install_property (object_class,
+ PROP_PARENT,
+ g_param_spec_object ("parent",
+ _("Parent Mission"),
+ _("Parent mission object to which this belongs"),
+ MCD_TYPE_MISSION,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_MODE,
+ g_param_spec_enum ("mode",
+ _("Platform-specific modes"),
+ _("Platform-specific modes"),
+ MCD_TYPE_MODE,
+ MCD_MODE_NORMAL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_SYSTEM_FLAGS,
+ g_param_spec_enum ("system-flags",
+ _("System flags"),
+ _("Mission control system flags"),
+ MCD_TYPE_MODE,
+ MCD_MODE_NORMAL,
+ G_PARAM_READWRITE));
+}
+
+static void
+mcd_mission_init (McdMission * obj)
+{
+}
+
+/* Public methods */
+
+McdMission *
+mcd_mission_new (void)
+{
+ McdMission *obj;
+
+ obj = MCD_MISSION (g_object_new (MCD_TYPE_MISSION, NULL));
+
+ return obj;
+}
+
+void
+mcd_mission_connect (McdMission * mission)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_MISSION_GET_CLASS (mission)->connect (mission);
+}
+
+void
+mcd_mission_disconnect (McdMission * mission)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_MISSION_GET_CLASS (mission)->disconnect (mission);
+}
+
+void
+mcd_mission_abort (McdMission * mission)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_MISSION_GET_CLASS (mission)->abort (mission);
+}
+
+McdSystemFlags
+mcd_mission_get_flags (McdMission * mission)
+{
+ g_return_val_if_fail (MCD_IS_MISSION (mission), 0);
+ return MCD_MISSION_GET_CLASS (mission)->get_flags (mission);
+}
+
+void
+mcd_mission_set_flags (McdMission * mission, McdSystemFlags flags)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_MISSION_GET_CLASS (mission)->set_flags (mission, flags);
+}
+
+McdMode
+mcd_mission_get_mode (McdMission * mission)
+{
+ g_return_val_if_fail (MCD_IS_MISSION (mission), MCD_MODE_UNKNOWN);
+ return MCD_MISSION_GET_CLASS (mission)->get_mode (mission);
+}
+
+void
+mcd_mission_set_mode (McdMission * mission, McdMode mode)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_MISSION_GET_CLASS (mission)->set_mode (mission, mode);
+}
+
+gboolean
+mcd_mission_is_connected (McdMission * mission)
+{
+ McdMissionPrivate *priv;
+
+ g_return_val_if_fail (MCD_IS_MISSION (mission), FALSE);
+ priv = MCD_MISSION_PRIV (mission);
+
+ return (priv->flags & MCD_SYSTEM_CONNECTED);
+}
+
+void
+mcd_mission_set_parent (McdMission * mission, McdMission * parent)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_MISSION_GET_CLASS (mission)->set_parent (mission, parent);
+}
+
+McdMission *
+mcd_mission_get_parent (McdMission * mission)
+{
+ McdMissionPrivate *priv;
+
+ g_return_val_if_fail (MCD_IS_MISSION (mission), NULL);
+ priv = MCD_MISSION_PRIV (mission);
+
+ return priv->parent;
+}
diff --git a/src/mcd-mission.h b/src/mcd-mission.h
new file mode 100644
index 00000000..0003e6a4
--- /dev/null
+++ b/src/mcd-mission.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_MISSION_H
+#define MCD_MISSION_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include "mcd-debug.h"
+
+G_BEGIN_DECLS
+
+#define MCD_TYPE_MISSION (mcd_mission_get_type ())
+#define MCD_MISSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_MISSION, McdMission))
+#define MCD_MISSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_MISSION, McdMissionClass))
+#define MCD_IS_MISSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_MISSION))
+#define MCD_IS_MISSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_MISSION))
+#define MCD_MISSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_MISSION, McdMissionClass))
+
+#define MCD_MISSION_GET_FLAGS_MASKED(mission, flags) \
+ (mcd_mission_get_flags (mission) & flags)
+
+#define MCD_MISSION_SET_FLAGS_MASKED(mission, flags) \
+ (mcd_mission_set_flags (mission, mcd_mission_get_flags (mission) | flags))
+
+#define MCD_MISSION_UNSET_FLAGS_MASKED(mission, flags) \
+ (mcd_mission_set_flags (mission, mcd_mission_get_flags (mission) & (~flags)))
+
+typedef enum
+{
+ MCD_MODE_UNKNOWN,
+ MCD_MODE_NORMAL,
+ MCD_MODE_RESTRICTED,
+ MCD_MODE_CALL
+} McdMode;
+
+typedef enum
+{
+ MCD_SYSTEM_CONNECTED = 1,
+ MCD_SYSTEM_MEMORY_CONSERVED = 1 << 1,
+ MCD_SYSTEM_POWER_CONSERVED = 1 << 2,
+ MCD_SYSTEM_SCREEN_BLANKED = 1 << 3,
+ MCD_SYSTEM_LOCKED = 1 << 4,
+ MCD_SYSTEM_IDLE = 1 << 5
+} McdSystemFlags;
+
+typedef struct _McdMission McdMission;
+typedef struct _McdMissionClass McdMissionClass;
+
+struct _McdMission
+{
+ GObject parent;
+};
+
+struct _McdMissionClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*parent_set_signal) (McdMission * mission, McdMission * parent);
+ void (*connected_signal) (McdMission * mission);
+ void (*disconnected_signal) (McdMission * mission);
+
+ void (*flags_changed_signal) (McdMission *mission, McdSystemFlags flags);
+ void (*mode_set_signal) (McdMission * mission, McdMode mode);
+
+ void (*abort_signal) (McdMission * mission);
+
+ /* Virtual methods */
+ void (*set_parent) (McdMission * mission, McdMission * parent);
+
+ void (*connect) (McdMission * mission);
+ void (*disconnect) (McdMission * mission);
+
+ void (*set_flags) (McdMission *mission, McdSystemFlags flags);
+ McdSystemFlags (*get_flags) (McdMission *mission);
+
+ void (*set_mode) (McdMission * mission, McdMode mode);
+ McdMode (*get_mode) (McdMission * mission);
+
+ void (*abort) (McdMission * mission);
+};
+
+GType mcd_mission_get_type (void);
+McdMission *mcd_mission_new (void);
+
+gboolean mcd_mission_is_connected (McdMission * mission);
+
+McdMission *mcd_mission_get_parent (McdMission * mission);
+
+void mcd_mission_abort (McdMission * mission);
+void mcd_mission_set_parent (McdMission * mission, McdMission * parent);
+
+void mcd_mission_connect (McdMission * mission);
+void mcd_mission_disconnect (McdMission * mission);
+
+void mcd_mission_set_flags (McdMission * mission, McdSystemFlags flags);
+McdSystemFlags mcd_mission_get_flags (McdMission * mission);
+
+void mcd_mission_set_mode (McdMission * mission, McdMode mode);
+McdMode mcd_mission_get_mode (McdMission * mission);
+
+G_END_DECLS
+#endif /* MCD_MISSION_H */
diff --git a/src/mcd-operation.c b/src/mcd-operation.c
new file mode 100644
index 00000000..face18bb
--- /dev/null
+++ b/src/mcd-operation.c
@@ -0,0 +1,313 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib/gi18n.h>
+#include "mcd-operation.h"
+
+#define MCD_OPERATION_PRIV(operation) (G_TYPE_INSTANCE_GET_PRIVATE ((operation), \
+ MCD_TYPE_OPERATION, \
+ McdOperationPrivate))
+
+/**
+ * McdOperation:
+ * This is a simple container class that can hold a list of mission objects
+ * as children. McdOperation makes sure that object states (see: McdMission)
+ * of the container are all proxied to the children. Children life cycles
+ * also managed by this class and parent-child relationship is correctly
+ * established.
+ */
+G_DEFINE_TYPE (McdOperation, mcd_operation, MCD_TYPE_MISSION);
+
+/* Private */
+
+typedef struct _McdOperationPrivate
+{
+ GList *missions;
+ gboolean is_disposed;
+} McdOperationPrivate;
+
+enum _McdOperationSignalType
+{
+ MISSION_TAKEN,
+ MISSION_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint mcd_operation_signals[LAST_SIGNAL] = { 0 };
+
+static void
+on_mission_abort (McdMission *mission, McdOperation *operation)
+{
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ g_return_if_fail (MCD_IS_OPERATION (operation));
+ mcd_operation_remove_mission (operation, mission);
+}
+
+static void
+_mcd_operation_disconnect_mission (McdMission *mission, McdOperation *operation)
+{
+ g_signal_handlers_disconnect_by_func (mission,
+ G_CALLBACK (on_mission_abort),
+ operation);
+}
+
+static void
+_mcd_operation_finalize (GObject * object)
+{
+ G_OBJECT_CLASS (mcd_operation_parent_class)->finalize (object);
+}
+
+static void
+_mcd_operation_child_unref (McdMission *child)
+{
+ g_object_unref (child);
+}
+
+static void
+_mcd_operation_abort (McdOperation * operation)
+{
+ const GList *node;
+
+ g_debug ("Operation abort received, aborting all children");
+ node = MCD_OPERATION_PRIV (operation)->missions;
+ while (node)
+ {
+ McdMission *mission = MCD_MISSION (node->data);
+ /* We don't want to hear it ourself so that we still hold the
+ * final reference to our children.
+ */
+ g_signal_handlers_disconnect_by_func (mission,
+ G_CALLBACK (on_mission_abort),
+ operation);
+ mcd_mission_abort (mission);
+
+ /* Restore the handler so that we continue listing for destroy
+ * notify for our children.
+ */
+ g_signal_connect (mission, "abort",
+ G_CALLBACK (on_mission_abort), operation);
+ node = g_list_next (node);
+ }
+}
+
+static void
+_mcd_operation_dispose (GObject * object)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+
+ priv->is_disposed = TRUE;
+ g_debug ("operation disposed");
+
+ g_signal_handlers_disconnect_by_func (object,
+ G_CALLBACK (_mcd_operation_abort),
+ NULL);
+ if (priv->missions)
+ {
+ g_list_foreach (priv->missions,
+ (GFunc) _mcd_operation_disconnect_mission,
+ object);
+ g_list_foreach (priv->missions, (GFunc) _mcd_operation_child_unref,
+ NULL);
+ g_list_free (priv->missions);
+ priv->missions = NULL;
+ }
+ G_OBJECT_CLASS (mcd_operation_parent_class)->dispose (object);
+}
+
+static void
+_mcd_operation_connect (McdMission * mission)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (mission);
+ g_list_foreach (priv->missions, (GFunc) mcd_mission_connect, NULL);
+ MCD_MISSION_CLASS (mcd_operation_parent_class)->connect (mission);
+}
+
+static void
+_mcd_operation_disconnect (McdMission * mission)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (mission);
+ g_list_foreach (priv->missions, (GFunc) mcd_mission_disconnect, NULL);
+ MCD_MISSION_CLASS (mcd_operation_parent_class)->disconnect (mission);
+}
+
+static void
+_mcd_operation_set_flags (McdMission * mission, McdSystemFlags flags)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (mission);
+ g_list_foreach (priv->missions, (GFunc) mcd_mission_set_flags,
+ GINT_TO_POINTER (flags));
+ MCD_MISSION_CLASS (mcd_operation_parent_class)->set_flags (mission, flags);
+}
+
+static void
+_mcd_operation_set_mode (McdMission * mission, McdMode mode)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (mission);
+ g_list_foreach (priv->missions, (GFunc) mcd_mission_set_mode,
+ GINT_TO_POINTER (mode));
+ MCD_MISSION_CLASS (mcd_operation_parent_class)->set_mode (mission, mode);
+}
+
+static void
+_mcd_operation_take_mission (McdOperation * operation, McdMission * mission)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (operation);
+ McdSystemFlags flags;
+ McdMode mode;
+
+ priv->missions = g_list_prepend (priv->missions, mission);
+ mcd_mission_set_parent (mission, MCD_MISSION (operation));
+
+ if (mcd_mission_is_connected (MCD_MISSION (operation)))
+ mcd_mission_connect (mission);
+ flags = mcd_mission_get_flags (MCD_MISSION (operation));
+ mcd_mission_set_flags (mission, flags);
+
+ mode = mcd_mission_get_mode (MCD_MISSION (operation));
+ mcd_mission_set_mode (mission, mode);
+
+ g_signal_connect (mission, "abort",
+ G_CALLBACK (on_mission_abort), operation);
+ g_signal_emit_by_name (G_OBJECT (operation), "mission-taken", mission);
+}
+
+static void
+_mcd_operation_remove_mission (McdOperation * operation, McdMission * mission)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (operation);
+
+ g_return_if_fail (g_list_find (priv->missions, mission) != NULL);
+
+ _mcd_operation_disconnect_mission (mission, operation);
+
+ priv->missions = g_list_remove (priv->missions, mission);
+ mcd_mission_set_parent (mission, NULL);
+
+ g_signal_emit_by_name (G_OBJECT (operation), "mission-removed", mission);
+
+ g_debug ("removing mission: %p", mission);
+ g_object_unref (mission);
+}
+
+static void
+mcd_operation_class_init (McdOperationClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ McdMissionClass *mission_class = MCD_MISSION_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (McdOperationPrivate));
+
+ object_class->finalize = _mcd_operation_finalize;
+ object_class->dispose = _mcd_operation_dispose;
+
+ mission_class->connect = _mcd_operation_connect;
+ mission_class->disconnect = _mcd_operation_disconnect;
+ mission_class->set_flags = _mcd_operation_set_flags;
+ mission_class->set_mode = _mcd_operation_set_mode;
+
+ klass->take_mission = _mcd_operation_take_mission;
+ klass->remove_mission = _mcd_operation_remove_mission;
+
+ mcd_operation_signals[MISSION_TAKEN] =
+ g_signal_new ("mission-taken",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdOperationClass,
+ mission_taken_signal),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+ mcd_operation_signals[MISSION_REMOVED] =
+ g_signal_new ("mission-removed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdOperationClass,
+ mission_removed_signal),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
+}
+
+static void
+mcd_operation_init (McdOperation * obj)
+{
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (obj);
+ priv->missions = NULL;
+
+ /* Listen to self abort so that we can propagate it to our
+ * children
+ */
+ g_signal_connect (obj, "abort", G_CALLBACK (_mcd_operation_abort), NULL);
+}
+
+/* Public */
+
+McdOperation *
+mcd_operation_new (void)
+{
+ McdOperation *obj;
+ obj = MCD_OPERATION (g_object_new (MCD_TYPE_OPERATION, NULL));
+ return obj;
+}
+
+void
+mcd_operation_take_mission (McdOperation * operation, McdMission * mission)
+{
+ g_return_if_fail (MCD_IS_OPERATION (operation));
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_OPERATION_GET_CLASS (operation)->take_mission (operation, mission);
+}
+
+void
+mcd_operation_remove_mission (McdOperation * operation, McdMission * mission)
+{
+ g_return_if_fail (MCD_IS_OPERATION (operation));
+ g_return_if_fail (MCD_IS_MISSION (mission));
+ MCD_OPERATION_GET_CLASS (operation)->remove_mission (operation, mission);
+}
+
+const GList *
+mcd_operation_get_missions (McdOperation * operation)
+{
+ g_return_val_if_fail (MCD_IS_OPERATION (operation), NULL);
+
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (operation);
+ return priv->missions;
+}
+
+void
+mcd_operation_foreach (McdOperation * operation, GFunc func, gpointer user_data)
+{
+ g_return_if_fail (MCD_IS_OPERATION (operation));
+
+ McdOperationPrivate *priv = MCD_OPERATION_PRIV (operation);
+
+ g_list_foreach (priv->missions, (GFunc) func, user_data);
+}
diff --git a/src/mcd-operation.h b/src/mcd-operation.h
new file mode 100644
index 00000000..ce61d51a
--- /dev/null
+++ b/src/mcd-operation.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_OPERATION_H
+#define MCD_OPERATION_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mcd-mission.h"
+
+G_BEGIN_DECLS
+#define MCD_TYPE_OPERATION (mcd_operation_get_type ())
+#define MCD_OPERATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_OPERATION, McdOperation))
+#define MCD_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_OPERATION, McdOperationClass))
+#define MCD_IS_OPERATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_OPERATION))
+#define MCD_IS_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_OPERATION))
+#define MCD_OPERATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_OPERATION, McdOperationClass))
+typedef struct _McdOperation McdOperation;
+typedef struct _McdOperationClass McdOperationClass;
+
+struct _McdOperation
+{
+ McdMission parent;
+};
+
+struct _McdOperationClass
+{
+ McdMissionClass parent_class;
+
+ /* signals */
+ void (*mission_taken_signal) (McdOperation * operation,
+ McdMission * mission);
+ void (*mission_removed_signal) (McdOperation * operation,
+ McdMission * mission);
+
+ /* virtual methods */
+ void (*take_mission) (McdOperation * operation, McdMission * mission);
+ void (*remove_mission) (McdOperation * operation, McdMission * mission);
+};
+
+GType mcd_operation_get_type (void);
+McdOperation *mcd_operation_new (void);
+
+/* Takes the ownership of mission */
+void mcd_operation_take_mission (McdOperation * operation,
+ McdMission * mission);
+void mcd_operation_remove_mission (McdOperation * operation,
+ McdMission * mission);
+void mcd_operation_foreach (McdOperation * operation,
+ GFunc func, gpointer user_data);
+const GList * mcd_operation_get_missions (McdOperation * operation);
+
+G_END_DECLS
+#endif /* MCD_OPERATION_H */
diff --git a/src/mcd-presence-frame.c b/src/mcd-presence-frame.c
new file mode 100644
index 00000000..8c6307c8
--- /dev/null
+++ b/src/mcd-presence-frame.c
@@ -0,0 +1,884 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "mcd-signals-marshal.h"
+#include "mcd-presence-frame.h"
+
+#define MCD_PRESENCE_FRAME_PRIV(pframe) (G_TYPE_INSTANCE_GET_PRIVATE ((pframe), \
+ MCD_TYPE_PRESENCE_FRAME, \
+ McdPresenceFramePrivate))
+
+G_DEFINE_TYPE (McdPresenceFrame, mcd_presence_frame, MCD_TYPE_MISSION);
+
+typedef struct _McdPresence
+{
+ McPresence presence;
+ gchar *message;
+ TelepathyConnectionStatus connection_status;
+ TelepathyConnectionStatusReason connection_reason;
+} McdPresence;
+
+typedef struct _McdPresenceFramePrivate
+{
+ McdPresence *requested_presence;
+ McdPresence *actual_presence;
+ McdPresence *last_presence;
+ GHashTable *account_presence;
+
+ gboolean is_stable;
+} McdPresenceFramePrivate;
+
+typedef struct _McdActualPresenceInfo {
+ McPresence presence;
+ McPresence requested_presence;
+ gboolean found;
+} McdActualPresenceInfo;
+
+enum _McdPresenceFrameSignalType
+{
+ /* Request */
+ PRESENCE_REQUESTED,
+
+ /* Account specific changes */
+ PRESENCE_CHANGED,
+ STATUS_CHANGED,
+
+ /* Accumulated changes */
+ PRESENCE_ACTUAL,
+ STATUS_ACTUAL,
+ PRESENCE_STABLE,
+
+ LAST_SIGNAL
+};
+
+static guint mcd_presence_frame_signals[LAST_SIGNAL] = { 0 };
+
+static McdPresence *
+mcd_presence_new (McPresence tp_presence,
+ const gchar * presence_message,
+ TelepathyConnectionStatus connection_status,
+ TelepathyConnectionStatusReason connection_reason)
+{
+ McdPresence *presence = g_new0 (McdPresence, 1);
+ presence->presence = tp_presence;
+ if (presence_message)
+ {
+ presence->message = g_strdup (presence_message);
+ }
+
+ else
+ {
+ presence->message = NULL;
+ }
+
+ presence->connection_status = connection_status;
+ presence->connection_reason = connection_reason;
+ return presence;
+}
+
+static void
+mcd_presence_free (McdPresence * presence)
+{
+ g_free (presence->message);
+ g_free (presence);
+}
+
+static McdPresence *
+mcd_presence_copy (McdPresence * presence)
+{
+ return mcd_presence_new (presence->presence,
+ presence->message,
+ presence->connection_status,
+ presence->connection_reason);
+}
+
+static void
+_mcd_presence_frame_dispose (GObject * object)
+{
+ McdPresenceFramePrivate *priv;
+
+ priv = MCD_PRESENCE_FRAME_PRIV (object);
+
+ if (priv->account_presence)
+ {
+ g_hash_table_destroy (priv->account_presence);
+ priv->account_presence = NULL;
+ }
+
+ G_OBJECT_CLASS (mcd_presence_frame_parent_class)->dispose (object);
+}
+
+static void
+_mcd_presence_frame_finalize (GObject * object)
+{
+ McdPresenceFrame *cobj;
+ McdPresenceFramePrivate *priv;
+
+ cobj = MCD_PRESENCE_FRAME (object);
+ priv = MCD_PRESENCE_FRAME_PRIV (object);
+
+ mcd_presence_free (priv->actual_presence);
+ if (priv->requested_presence)
+ mcd_presence_free (priv->requested_presence);
+ if (priv->last_presence)
+ mcd_presence_free (priv->last_presence);
+
+ G_OBJECT_CLASS (mcd_presence_frame_parent_class)->finalize (object);
+}
+
+static void
+mcd_presence_frame_disconnect (McdMission *mission)
+{
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (mission);
+
+ /* If connectivity goes away MC will abort processing a presence request;
+ * so we must clear the requested-presence for consistency, or McdMaster
+ * will think we are still trying to go online. */
+ if (priv->requested_presence)
+ {
+ mcd_presence_free (priv->requested_presence);
+ priv->requested_presence = NULL;
+ }
+}
+
+static void
+mcd_presence_frame_class_init (McdPresenceFrameClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ McdMissionClass *mission_class = MCD_MISSION_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (McdPresenceFramePrivate));
+
+ object_class->dispose = _mcd_presence_frame_dispose;
+ object_class->finalize = _mcd_presence_frame_finalize;
+ mission_class->disconnect = mcd_presence_frame_disconnect;
+
+ /* FIXME: Telepathy doesn't currently registers it's enums to glib so we are compelled to register the
+ * signal handler's arguments as INTs below */
+ /* signals */
+ mcd_presence_frame_signals[PRESENCE_REQUESTED] =
+ g_signal_new ("presence-requested",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdPresenceFrameClass,
+ presence_requested_signal),
+ NULL, NULL,
+ mcd_marshal_VOID__INT_STRING,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING);
+ mcd_presence_frame_signals[PRESENCE_CHANGED] =
+ g_signal_new ("presence-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdPresenceFrameClass,
+ presence_set_signal),
+ NULL, NULL,
+ mcd_marshal_VOID__OBJECT_INT_STRING,
+ G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_INT, G_TYPE_STRING);
+ mcd_presence_frame_signals[STATUS_CHANGED] =
+ g_signal_new ("status-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdPresenceFrameClass,
+ status_changed_signal),
+ NULL, NULL,
+ mcd_marshal_VOID__OBJECT_INT_INT,
+ G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_INT, G_TYPE_INT);
+ mcd_presence_frame_signals[PRESENCE_ACTUAL] =
+ g_signal_new ("presence-actual",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdPresenceFrameClass,
+ presence_actual_signal),
+ NULL, NULL,
+ mcd_marshal_VOID__INT_STRING,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING);
+ mcd_presence_frame_signals[STATUS_ACTUAL] =
+ g_signal_new ("status-actual",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (McdPresenceFrameClass,
+ status_actual_signal),
+ NULL, NULL,
+ mcd_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ mcd_presence_frame_signals[PRESENCE_STABLE] =
+ g_signal_new ("presence-stable",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ mcd_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+}
+
+static void
+mcd_presence_frame_init (McdPresenceFrame * obj)
+{
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (obj);
+
+ priv->account_presence =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) mcd_presence_free);
+
+ priv->actual_presence = mcd_presence_new (MC_PRESENCE_UNSET,
+ NULL,
+ TP_CONN_STATUS_DISCONNECTED,
+ TP_CONN_STATUS_REASON_NONE_SPECIFIED);
+ priv->requested_presence = NULL;
+ priv->last_presence = NULL;
+
+ priv->is_stable = TRUE;
+}
+
+/* Public */
+
+McdPresenceFrame *
+mcd_presence_frame_new (void)
+{
+ McdPresenceFrame *obj;
+ obj = MCD_PRESENCE_FRAME (g_object_new (MCD_TYPE_PRESENCE_FRAME, NULL));
+ return obj;
+}
+
+static void
+_mcd_presence_frame_print_account (McAccount *account, McdPresence *presence,
+ McdPresenceFrame *presence_frame)
+{
+ g_debug (" Account: %s", mc_account_get_unique_name (account));
+ if (presence->message)
+ {
+ g_debug (" Presence = %d, Status = %d, Message = %s",
+ presence->presence, presence->connection_status,
+ presence->message);
+ }
+ else
+ {
+ g_debug (" Presence = %d, Status = %d",
+ presence->presence, presence->connection_status);
+ }
+}
+
+static void
+_mcd_presence_frame_print (McdPresenceFrame *presence_frame)
+{
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ g_debug ("PresenceFrame state:");
+ g_debug ("[");
+ g_hash_table_foreach (priv->account_presence,
+ (GHFunc)_mcd_presence_frame_print_account,
+ presence_frame);
+ g_debug ("]");
+}
+
+static void
+_mcd_presence_frame_request_presence (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ const gchar * presence_message)
+{
+ McdPresenceFramePrivate *priv;
+ TelepathyConnectionStatus status;
+
+ g_return_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame));
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->requested_presence)
+ {
+ mcd_presence_free (priv->requested_presence);
+ }
+
+ if (presence == MC_PRESENCE_OFFLINE)
+ {
+ status = TP_CONN_STATUS_DISCONNECTED;
+ }
+
+ else
+ {
+ status = TP_CONN_STATUS_CONNECTED;
+ }
+
+ priv->requested_presence = mcd_presence_new (presence, presence_message,
+ status,
+ TP_CONN_STATUS_REASON_REQUESTED);
+ g_debug ("%s: Presence %d is being requested", G_STRFUNC, presence);
+
+ g_signal_emit_by_name (presence_frame, "presence-requested",
+ presence, presence_message);
+}
+
+void
+mcd_presence_frame_request_presence (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ const gchar * presence_message)
+{
+ McdPresenceFramePrivate *priv;
+
+ g_return_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame));
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->last_presence)
+ {
+ mcd_presence_free (priv->last_presence);
+ }
+ priv->last_presence = mcd_presence_copy (priv->actual_presence);
+
+ g_debug ("%s: updated last_presence = %d, msg = %s", G_STRFUNC,
+ priv->last_presence->presence,
+ priv->last_presence->message);
+
+ if (priv->last_presence->presence == MC_PRESENCE_UNSET)
+ {
+ priv->last_presence->presence = MC_PRESENCE_OFFLINE;
+ }
+
+ if (mcd_debug_get_level() > 0)
+ {
+ g_debug ("Presence requested: %d", presence);
+ _mcd_presence_frame_print (presence_frame);
+ }
+
+ _mcd_presence_frame_request_presence (presence_frame, presence,
+ presence_message);
+}
+
+gboolean
+mcd_presence_frame_cancel_last_request (McdPresenceFrame * presence_frame)
+{
+ McdPresenceFramePrivate *priv;
+ McPresence presence;
+ gchar *message;
+
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame), FALSE);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->last_presence != NULL)
+ {
+ presence = priv->last_presence->presence;
+ if (priv->last_presence->message)
+ {
+ message = g_strdup (priv->last_presence->message);
+ }
+
+ else
+ {
+ message = NULL;
+ }
+
+ mcd_presence_free (priv->last_presence);
+ priv->last_presence = NULL;
+
+ _mcd_presence_frame_request_presence (presence_frame, presence,
+ message);
+ return TRUE;
+ }
+
+ else
+ {
+ return FALSE;
+ }
+}
+
+McPresence
+mcd_presence_frame_get_requested_presence (McdPresenceFrame * presence_frame)
+{
+ McdPresenceFramePrivate *priv;
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame),
+ MC_PRESENCE_UNSET);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->requested_presence)
+ return priv->requested_presence->presence;
+ else
+ return MC_PRESENCE_UNSET;
+}
+
+const gchar *
+mcd_presence_frame_get_requested_presence_message (McdPresenceFrame *
+ presence_frame)
+{
+ McdPresenceFramePrivate *priv;
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame), NULL);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->requested_presence)
+ return priv->requested_presence->message;
+ else
+ return NULL;
+}
+
+McPresence
+mcd_presence_frame_get_actual_presence (McdPresenceFrame * presence_frame)
+{
+ McdPresenceFramePrivate *priv;
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame),
+ MC_PRESENCE_UNSET);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ return priv->actual_presence->presence;
+}
+
+const gchar *
+mcd_presence_frame_get_actual_presence_message (McdPresenceFrame *
+ presence_frame)
+{
+ McdPresenceFramePrivate *priv;
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame), NULL);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ return priv->actual_presence->message;
+}
+
+static void
+_mcd_presence_frame_update_actual_presences (gpointer key,
+ gpointer val,
+ McdActualPresenceInfo *info)
+{
+ McdPresence *account_presence = (McdPresence *) val;
+
+ if (info->found) return;
+ if (account_presence->presence == info->requested_presence)
+ {
+ info->presence = account_presence->presence;
+ info->found = TRUE;
+ }
+ else if (info->presence < account_presence->presence)
+ info->presence = account_presence->presence;
+}
+
+static void
+_mcd_presence_frame_update_actual_presence (McdPresenceFrame * presence_frame,
+ const gchar * presence_message)
+{
+ McdPresenceFramePrivate *priv;
+ McdActualPresenceInfo pi;
+ McPresence old_presence;
+ TelepathyConnectionStatus connection_status;
+ TelepathyConnectionStatusReason connection_reason;
+
+ g_debug ("%s called", G_STRFUNC);
+
+ pi.presence = MC_PRESENCE_UNSET;
+ pi.requested_presence = mcd_presence_frame_get_requested_presence (presence_frame);
+ pi.found = FALSE;
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+ g_hash_table_foreach (priv->account_presence,
+ (GHFunc)_mcd_presence_frame_update_actual_presences,
+ &pi);
+
+ connection_status = priv->actual_presence->connection_status;
+ connection_reason = priv->actual_presence->connection_reason;
+
+ old_presence = priv->actual_presence->presence;
+ mcd_presence_free (priv->actual_presence);
+ priv->actual_presence = mcd_presence_new (pi.presence,
+ presence_message,
+ connection_status,
+ connection_reason);
+
+ g_debug ("%s: presence actual: %d", G_STRFUNC, pi.presence);
+ if (old_presence != pi.presence)
+ {
+ g_signal_emit_by_name (G_OBJECT (presence_frame),
+ "presence-actual", pi.presence, presence_message);
+ }
+}
+
+void
+mcd_presence_frame_set_account_presence (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ McPresence
+ presence,
+ const gchar * presence_message)
+{
+ McdPresenceFramePrivate *priv;
+ McdPresence *account_presence;
+
+ g_return_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame));
+
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+ account_presence = g_hash_table_lookup (priv->account_presence, account);
+
+ g_return_if_fail (account_presence != NULL);
+ if (account_presence->presence == presence)
+ {
+ g_debug ("%s: presence already set, not setting", G_STRFUNC);
+ return;
+ }
+
+ g_debug ("%s: changing presence of account %s from %d to %d",
+ G_STRFUNC, mc_account_get_unique_name (account),
+ account_presence->presence,
+ presence);
+ account_presence->presence = presence;
+ g_free (account_presence->message);
+ account_presence->message = NULL;
+ if (presence_message)
+ account_presence->message = g_strdup (presence_message);
+
+ g_signal_emit_by_name (presence_frame, "presence-changed", account,
+ presence, presence_message);
+
+ _mcd_presence_frame_update_actual_presence (presence_frame,
+ presence_message);
+
+ if (mcd_debug_get_level() > 0)
+ {
+ g_debug ("Presence Set for account: %s: %d",
+ mc_account_get_unique_name (account),
+ presence);
+ _mcd_presence_frame_print (presence_frame);
+ }
+
+}
+
+McPresence
+mcd_presence_frame_get_account_presence (McdPresenceFrame * presence_frame,
+ McAccount * account)
+{
+ McdPresenceFramePrivate *priv;
+ McPresence ret_presence;
+
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame),
+ MC_PRESENCE_UNSET);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ ret_presence = MC_PRESENCE_UNSET;
+ if (priv->account_presence)
+ {
+ McdPresence *presence;
+ presence = g_hash_table_lookup (priv->account_presence, account);
+ if (presence)
+ ret_presence = presence->presence;
+ }
+ return ret_presence;
+}
+
+const gchar *
+mcd_presence_frame_get_account_presence_message (McdPresenceFrame *
+ presence_frame,
+ McAccount * account)
+{
+ McdPresenceFramePrivate *priv;
+
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame), NULL);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->account_presence)
+ {
+ McdPresence *presence;
+ presence = g_hash_table_lookup (priv->account_presence, account);
+ if (presence)
+ return presence->message;
+ }
+ return NULL;
+}
+
+static void
+_mcd_presence_frame_update_actual_statuses (gpointer key,
+ gpointer val, gpointer user_data)
+{
+ McdPresence *account_presence = (McdPresence *) val;
+ TelepathyConnectionStatus *connection_status =
+ (TelepathyConnectionStatus *) user_data;
+
+ if (*connection_status > account_presence->connection_status)
+ *connection_status = account_presence->connection_status;
+}
+
+static void
+_mcd_presence_frame_update_actual_status (McdPresenceFrame * presence_frame)
+{
+ McdPresenceFramePrivate *priv;
+ TelepathyConnectionStatus connection_status = TP_CONN_STATUS_DISCONNECTED;
+ TelepathyConnectionStatus old_connection_status;
+ TelepathyConnectionStatusReason connection_reason;
+ McPresence presence;
+ gchar *presence_message = NULL;
+
+ g_debug ("%s called", G_STRFUNC);
+
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+ g_hash_table_foreach (priv->account_presence,
+ _mcd_presence_frame_update_actual_statuses,
+ &connection_status);
+
+ connection_reason = priv->actual_presence->connection_reason;
+ presence = priv->actual_presence->presence;
+ if (priv->actual_presence->message)
+ presence_message = g_strdup (priv->actual_presence->message);
+
+ old_connection_status = priv->actual_presence->connection_status;
+ mcd_presence_free (priv->actual_presence);
+ priv->actual_presence = mcd_presence_new (presence,
+ presence_message,
+ connection_status,
+ connection_reason);
+
+ g_debug ("%s: status actual: %d", G_STRFUNC, connection_status);
+ if (old_connection_status != connection_status)
+ g_signal_emit_by_name (G_OBJECT (presence_frame), "status-actual",
+ connection_status);
+}
+
+static void
+_mcd_presence_frame_check_stable (McAccount *account, McdPresence *presence, gboolean *stable)
+{
+ g_debug ("%s: status = %d", G_STRFUNC, presence->connection_status);
+ if (presence->connection_status == TP_CONN_STATUS_CONNECTING)
+ *stable = FALSE;
+}
+
+static void
+_mcd_presence_frame_update_stable (McdPresenceFrame *presence_frame)
+{
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ g_debug ("%s: account_presence = %p", G_STRFUNC, priv->account_presence);
+ priv->is_stable = TRUE;
+ if (priv->account_presence)
+ g_hash_table_foreach (priv->account_presence,
+ (GHFunc)_mcd_presence_frame_check_stable,
+ &priv->is_stable);
+}
+
+void
+mcd_presence_frame_set_account_status (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ TelepathyConnectionStatus
+ connection_status,
+ TelepathyConnectionStatusReason
+ connection_reason)
+{
+ McdPresenceFramePrivate *priv;
+ McdPresence *account_presence;
+ TelepathyConnectionStatus previous_status;
+ gboolean was_stable;
+
+ g_return_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame));
+
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+ account_presence = g_hash_table_lookup (priv->account_presence, account);
+
+ if (account_presence == NULL)
+ {
+ g_warning ("%s: Can not find account presence for account %p (%s)",
+ G_STRFUNC, account,
+ mc_account_get_unique_name (account));
+ return;
+ }
+
+ previous_status = account_presence->connection_status;
+ account_presence->connection_status = connection_status;
+ account_presence->connection_reason = connection_reason;
+
+ /* If no changed, then return */
+ if (previous_status == connection_status)
+ return;
+
+ if (connection_status == TP_CONN_STATUS_DISCONNECTED)
+ {
+ /* We first set UNSET presence */
+ mcd_presence_frame_set_account_presence (presence_frame, account,
+ MC_PRESENCE_UNSET,
+ NULL);
+ /* and then set DISCONNECTED */
+ g_signal_emit_by_name (presence_frame, "status-changed", account,
+ connection_status, connection_reason);
+ _mcd_presence_frame_update_actual_status (presence_frame);
+ }
+ else if (connection_status == TP_CONN_STATUS_CONNECTING)
+ {
+ g_signal_emit_by_name (presence_frame, "status-changed", account,
+ connection_status, connection_reason);
+ _mcd_presence_frame_update_actual_status (presence_frame);
+ }
+ else if (connection_status == TP_CONN_STATUS_CONNECTED)
+ {
+ /* We first set CONNECTED */
+ g_signal_emit_by_name (presence_frame, "status-changed", account,
+ connection_status, connection_reason);
+ _mcd_presence_frame_update_actual_status (presence_frame);
+
+ /* and then set AVAILABLE presence */
+ mcd_presence_frame_set_account_presence (presence_frame, account,
+ MC_PRESENCE_AVAILABLE,
+ NULL);
+ }
+
+ was_stable = priv->is_stable;
+ _mcd_presence_frame_update_stable (presence_frame);
+ if (was_stable != priv->is_stable || priv->is_stable)
+ g_signal_emit (presence_frame,
+ mcd_presence_frame_signals[PRESENCE_STABLE],
+ 0, priv->is_stable);
+
+ if (mcd_debug_get_level() > 0)
+ {
+ g_debug ("%s: was stable = %d, is_stable = %d", G_STRFUNC, was_stable, priv->is_stable);
+ g_debug ("Account Status Set for account: %s: %d", mc_account_get_unique_name (account),
+ connection_status);
+ _mcd_presence_frame_print (presence_frame);
+ }
+}
+
+TelepathyConnectionStatus
+mcd_presence_frame_get_account_status (McdPresenceFrame * presence_frame,
+ McAccount * account)
+{
+ McdPresenceFramePrivate *priv;
+ TelepathyConnectionStatus conn_status;
+
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame),
+ TP_CONN_STATUS_DISCONNECTED);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ conn_status = TP_CONN_STATUS_DISCONNECTED;
+ if (priv->account_presence)
+ {
+ McdPresence *presence;
+ presence = g_hash_table_lookup (priv->account_presence, account);
+ if (presence)
+ conn_status = presence->connection_status;
+ }
+ return conn_status;
+}
+
+TelepathyConnectionStatusReason
+mcd_presence_frame_get_account_status_reason (McdPresenceFrame *
+ presence_frame,
+ McAccount * account)
+{
+ McdPresenceFramePrivate *priv;
+ TelepathyConnectionStatusReason conn_reason;
+
+ g_return_val_if_fail (MCD_IS_PRESENCE_FRAME (presence_frame),
+ TP_CONN_STATUS_REASON_NONE_SPECIFIED);
+ priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ conn_reason = TP_CONN_STATUS_REASON_NONE_SPECIFIED;
+ if (priv->account_presence)
+ {
+ McdPresence *presence;
+ presence = g_hash_table_lookup (priv->account_presence, account);
+ if (presence)
+ conn_reason = presence->connection_reason;
+ }
+ return conn_reason;
+}
+
+void
+mcd_presence_frame_set_accounts (McdPresenceFrame * presence_frame,
+ const GList * accounts)
+{
+ const GList *node;
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ if (priv->account_presence)
+ {
+ g_hash_table_destroy (priv->account_presence);
+ priv->account_presence =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) mcd_presence_free);
+ }
+ for (node = accounts; node; node = node->next)
+ {
+ g_object_ref (node->data);
+ g_hash_table_insert (priv->account_presence, node->data,
+ mcd_presence_new (MC_PRESENCE_UNSET,
+ NULL,
+ TP_CONN_STATUS_DISCONNECTED,
+ TP_CONN_STATUS_REASON_NONE_SPECIFIED));
+ }
+}
+
+gboolean
+mcd_presence_frame_add_account (McdPresenceFrame * presence_frame,
+ McAccount * account)
+{
+ McdPresence *presence;
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ /* Let's see if we already have the account */
+ presence = g_hash_table_lookup (priv->account_presence, account);
+
+ if (presence != NULL)
+ {
+ return FALSE;
+ }
+
+ presence = mcd_presence_new (MC_PRESENCE_UNSET,
+ NULL,
+ TP_CONN_STATUS_DISCONNECTED,
+ TP_CONN_STATUS_REASON_NONE_SPECIFIED);
+ g_object_ref (account);
+ g_hash_table_insert (priv->account_presence,
+ account,
+ presence);
+
+ /*mcd_presence_frame_set_account_presence (presence_frame, account,
+ priv->actual_presence->presence,
+ NULL);*/
+ return TRUE;
+}
+
+gboolean
+mcd_presence_frame_remove_account (McdPresenceFrame * presence_frame,
+ McAccount * account)
+{
+ McdPresence *presence;
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+
+ /* Let's see if we have the account */
+ presence = g_hash_table_lookup (priv->account_presence, account);
+
+ if (presence == NULL)
+ {
+ return FALSE;
+ }
+
+ g_debug ("%s: removing account %s", G_STRFUNC, mc_account_get_unique_name (account));
+ /*mcd_presence_frame_set_account_presence (presence_frame, account,
+ MC_PRESENCE_UNSET,
+ NULL);*/
+ /*_mcd_presence_frame_update_actual_presence (presence_frame, NULL);*/
+ g_hash_table_remove (priv->account_presence, account);
+
+ return TRUE;
+}
+
+/**
+ * mcd_presence_frame_is_stable:
+ * @presence_frame: The #McdPresenceFrame.
+ *
+ * Returns #TRUE if there isn't any account currently trying to connect.
+ */
+gboolean
+mcd_presence_frame_is_stable (McdPresenceFrame *presence_frame)
+{
+ McdPresenceFramePrivate *priv = MCD_PRESENCE_FRAME_PRIV (presence_frame);
+ return priv->is_stable;
+}
+
diff --git a/src/mcd-presence-frame.h b/src/mcd-presence-frame.h
new file mode 100644
index 00000000..06b4d17f
--- /dev/null
+++ b/src/mcd-presence-frame.h
@@ -0,0 +1,133 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_PRESENCE_FRAME_H
+#define MCD_PRESENCE_FRAME_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libtelepathy/tp-constants.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include "mcd-mission.h"
+
+G_BEGIN_DECLS
+#define MCD_TYPE_PRESENCE_FRAME (mcd_presence_frame_get_type ())
+#define MCD_PRESENCE_FRAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_PRESENCE_FRAME, McdPresenceFrame))
+#define MCD_PRESENCE_FRAME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_PRESENCE_FRAME, McdPresenceFrameClass))
+#define MCD_IS_PRESENCE_FRAME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_PRESENCE_FRAME))
+#define MCD_IS_PRESENCE_FRAME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_PRESENCE_FRAME))
+#define MCD_PRESENCE_FRAME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_PRESENCE_FRAME, McdPresenceFrameClass))
+typedef struct _McdPresenceFrame McdPresenceFrame;
+typedef struct _McdPresenceFrameClass McdPresenceFrameClass;
+
+struct _McdPresenceFrame
+{
+ McdMission parent;
+};
+
+struct _McdPresenceFrameClass
+{
+ McdMissionClass parent_class;
+
+ /* Signals */
+ void (*presence_requested_signal) (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ const gchar * presence_message);
+
+ /* Account specific signals */
+ void (*presence_set_signal) (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ McPresence presence,
+ const gchar * presence_message);
+ void (*status_changed_signal) (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ TelepathyConnectionStatus connection_status,
+ TelepathyConnectionStatusReason
+ connection_reason);
+
+ /* Aggregate signals */
+ void (*presence_actual_signal) (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ const gchar * presence_message);
+ void (*status_actual_signal) (McdPresenceFrame * presence_frame,
+ TelepathyConnectionStatus status);
+};
+
+GType mcd_presence_frame_get_type (void);
+McdPresenceFrame *mcd_presence_frame_new (void);
+
+void mcd_presence_frame_request_presence (McdPresenceFrame * presence_frame,
+ McPresence
+ presence,
+ const gchar * presence_message);
+
+McPresence mcd_presence_frame_get_requested_presence
+ (McdPresenceFrame * presence_frame);
+const gchar *mcd_presence_frame_get_requested_presence_message
+ (McdPresenceFrame * presence_frame);
+
+McPresence mcd_presence_frame_get_actual_presence
+ (McdPresenceFrame * presence_frame);
+const gchar *mcd_presence_frame_get_actual_presence_message
+ (McdPresenceFrame * presence_frame);
+
+void mcd_presence_frame_set_account_presence (McdPresenceFrame *
+ presence_frame,
+ McAccount * account,
+ McPresence
+ presence,
+ const gchar * presence_message);
+void mcd_presence_frame_set_account_status (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ TelepathyConnectionStatus
+ connection_status,
+ TelepathyConnectionStatusReason
+ connection_reason);
+
+McPresence mcd_presence_frame_get_account_presence
+ (McdPresenceFrame * presence_frame, McAccount * account);
+const gchar *mcd_presence_frame_get_presence_message
+ (McdPresenceFrame * presence_frame, McAccount * account);
+TelepathyConnectionStatus mcd_presence_frame_get_account_status
+ (McdPresenceFrame * presence_frame, McAccount * account);
+TelepathyConnectionStatusReason mcd_presence_frame_get_account_status_reason
+ (McdPresenceFrame * presence_frame, McAccount * account);
+
+void mcd_presence_frame_set_accounts (McdPresenceFrame * presence_frame,
+ const GList * accounts);
+
+gboolean mcd_presence_frame_add_account (McdPresenceFrame * presence_frame,
+ McAccount * account);
+gboolean mcd_presence_frame_remove_account (McdPresenceFrame * presence_frame,
+ McAccount * account);
+
+gboolean mcd_presence_frame_cancel_last_request (McdPresenceFrame *
+ presence_frame);
+
+gboolean mcd_presence_frame_is_stable (McdPresenceFrame *presence_frame);
+
+G_END_DECLS
+#endif /* MCD_PRESENCE_FRAME_H */
diff --git a/src/mcd-proxy.c b/src/mcd-proxy.c
new file mode 100644
index 00000000..ff163e1a
--- /dev/null
+++ b/src/mcd-proxy.c
@@ -0,0 +1,226 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib/gi18n.h>
+#include "mcd-proxy.h"
+
+#define MCD_PROXY_PRIV(proxy) (G_TYPE_INSTANCE_GET_PRIVATE ((proxy), \
+ MCD_TYPE_PROXY, \
+ McdProxyPrivate))
+
+/**
+ * McdProxy:
+ * This is a simple container class that proxies the events from a proxy
+ * object to self container.
+ */
+G_DEFINE_TYPE (McdProxy, mcd_proxy, MCD_TYPE_OPERATION);
+
+/* Private */
+
+typedef struct _McdProxyPrivate
+{
+ McdMission *proxy_object;
+ gboolean is_disposed;
+} McdProxyPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_PROXY_OBJECT
+};
+
+static void
+_mcd_proxy_abort (McdProxy * proxy)
+{
+ /* Releases the reference */
+ g_object_set (proxy, "proxy-object", NULL, NULL);
+ /* Propagate the "abort" event to our listeners */
+ mcd_mission_abort (MCD_MISSION (proxy));
+}
+
+static void
+_mcd_proxy_connect_signals (McdProxy * proxy)
+{
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (proxy);
+
+ g_signal_connect_swapped (priv->proxy_object, "connected",
+ G_CALLBACK (mcd_mission_connect), proxy);
+ g_signal_connect_swapped (priv->proxy_object, "disconnected",
+ G_CALLBACK (mcd_mission_disconnect), proxy);
+ g_signal_connect_swapped (priv->proxy_object, "flags-changed",
+ G_CALLBACK (mcd_mission_set_flags), proxy);
+ g_signal_connect_swapped (priv->proxy_object, "mode-set",
+ G_CALLBACK (mcd_mission_set_mode), proxy);
+ g_signal_connect_swapped (priv->proxy_object, "abort",
+ G_CALLBACK (_mcd_proxy_abort), proxy);
+}
+
+static void
+_mcd_proxy_disconnect_signals (McdProxy * proxy)
+{
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (proxy);
+
+ g_signal_handlers_disconnect_by_func (priv->proxy_object,
+ G_CALLBACK (mcd_mission_connect),
+ proxy);
+ g_signal_handlers_disconnect_by_func (priv->proxy_object,
+ G_CALLBACK (mcd_mission_disconnect),
+ proxy);
+ g_signal_handlers_disconnect_by_func (priv->proxy_object,
+ G_CALLBACK (mcd_mission_set_flags),
+ proxy);
+ g_signal_handlers_disconnect_by_func (priv->proxy_object,
+ G_CALLBACK (mcd_mission_set_mode),
+ proxy);
+ g_signal_handlers_disconnect_by_func (priv->proxy_object,
+ G_CALLBACK (_mcd_proxy_abort), proxy);
+}
+
+static void
+_mcd_proxy_finalize (GObject * object)
+{
+ G_OBJECT_CLASS (mcd_proxy_parent_class)->finalize (object);
+}
+
+static void
+_mcd_proxy_dispose (GObject * object)
+{
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (object);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+
+ priv->is_disposed = TRUE;
+ g_debug ("proxy disposed\n");
+
+ if (priv->proxy_object)
+ {
+ /* Disconnect proxy signals */
+ _mcd_proxy_disconnect_signals (MCD_PROXY (object));
+ g_object_unref (priv->proxy_object);
+ priv->proxy_object = NULL;
+ }
+ G_OBJECT_CLASS (mcd_proxy_parent_class)->dispose (object);
+}
+
+static void
+_mcd_proxy_set_property (GObject * obj, guint prop_id,
+ const GValue * val, GParamSpec * pspec)
+{
+ McdMission *proxy_object;
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_PROXY_OBJECT:
+ proxy_object = g_value_get_object (val);
+ if (proxy_object)
+ {
+ g_return_if_fail (MCD_IS_MISSION (proxy_object));
+ g_object_ref (proxy_object);
+ }
+
+ if (priv->proxy_object)
+ {
+ /* Disconnect proxy signals */
+ _mcd_proxy_disconnect_signals (MCD_PROXY (obj));
+ g_object_unref (priv->proxy_object);
+ }
+ priv->proxy_object = proxy_object;
+ if (priv->proxy_object)
+ {
+ /* Connect proxy signals */
+ _mcd_proxy_connect_signals (MCD_PROXY (obj));
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_mcd_proxy_get_property (GObject * obj, guint prop_id,
+ GValue * val, GParamSpec * pspec)
+{
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (obj);
+
+ switch (prop_id)
+ {
+ case PROP_PROXY_OBJECT:
+ g_value_set_pointer (val, priv->proxy_object);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mcd_proxy_class_init (McdProxyClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (McdProxyPrivate));
+
+ object_class->finalize = _mcd_proxy_finalize;
+ object_class->dispose = _mcd_proxy_dispose;
+ object_class->set_property = _mcd_proxy_set_property;
+ object_class->get_property = _mcd_proxy_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_PROXY_OBJECT,
+ g_param_spec_object ("proxy-object",
+ _("Proxy object"),
+ _("Object to be monitored for McdMission signals"),
+ MCD_TYPE_MISSION,
+ G_PARAM_READWRITE));
+}
+
+static void
+mcd_proxy_init (McdProxy * obj)
+{
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (obj);
+ priv->proxy_object = NULL;
+}
+
+/* Public */
+
+McdProxy *
+mcd_proxy_new (McdMission * proxy_object)
+{
+ McdProxy *obj;
+ obj = MCD_PROXY (g_object_new (MCD_TYPE_PROXY, "proxy-object",
+ proxy_object, NULL));
+ return obj;
+}
+
+const McdMission *
+mcd_proxy_get_proxy_object (McdProxy * proxy)
+{
+ McdProxyPrivate *priv = MCD_PROXY_PRIV (proxy);
+ return priv->proxy_object;
+}
diff --git a/src/mcd-proxy.h b/src/mcd-proxy.h
new file mode 100644
index 00000000..ed0aac6e
--- /dev/null
+++ b/src/mcd-proxy.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_PROXY_H
+#define MCD_PROXY_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mcd-operation.h"
+
+G_BEGIN_DECLS
+#define MCD_TYPE_PROXY (mcd_proxy_get_type ())
+#define MCD_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_PROXY, McdProxy))
+#define MCD_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MCD_TYPE_PROXY, McdProxyClass))
+#define MCD_IS_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_PROXY))
+#define MCD_IS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MCD_TYPE_PROXY))
+#define MCD_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_PROXY, McdProxyClass))
+typedef struct _McdProxy McdProxy;
+typedef struct _McdProxyClass McdProxyClass;
+
+struct _McdProxy
+{
+ McdOperation parent;
+};
+
+struct _McdProxyClass
+{
+ McdOperationClass parent_class;
+};
+
+GType mcd_proxy_get_type (void);
+McdProxy *mcd_proxy_new (McdMission * proxy_mission);
+const McdMission *mcd_proxy_get_proxy_object (McdProxy * proxy);
+
+G_END_DECLS
+#endif /* MCD_PROXY_H */
diff --git a/src/mcd-service.c b/src/mcd-service.c
new file mode 100644
index 00000000..690695f1
--- /dev/null
+++ b/src/mcd-service.c
@@ -0,0 +1,789 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <dbus/dbus.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <sched.h>
+#include <libmissioncontrol/mission-control.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus.h>
+#include <gconf/gconf-client.h>
+#include <libtelepathy/tp-interfaces.h>
+#include <libtelepathy/tp-constants.h>
+
+#include "mcd-signals-marshal.h"
+#include "mcd-dispatcher.h"
+#include "mcd-connection.h"
+#include "mcd-service.h"
+
+/* DBus service specifics */
+#define MISSION_CONTROL_DBUS_SERVICE "org.freedesktop.Telepathy.MissionControl"
+#define MISSION_CONTROL_DBUS_OBJECT "/org/freedesktop/Telepathy/MissionControl"
+#define MISSION_CONTROL_DBUS_IFACE "org.freedesktop.Telepathy.MissionControl"
+
+/* Signals */
+
+enum
+{
+ ACCOUNT_STATUS_CHANGED,
+ ERROR,
+ PRESENCE_STATUS_REQUESTED,
+ PRESENCE_STATUS_ACTUAL,
+ USED_CHANNELS_COUNT_CHANGED,
+ STATUS_ACTUAL,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+static GObjectClass *parent_class = NULL;
+
+#define MCD_OBJECT_PRIV(mission) (G_TYPE_INSTANCE_GET_PRIVATE ((mission), \
+ MCD_TYPE_SERVICE, \
+ McdServicePrivate))
+
+/**
+ * McdService:
+ * It is the frontline interface object that exposes mission-control to outside
+ * world through a dbus interface. It basically subclasses McdMaster and
+ * wraps up everything inside it and translate them into mission-control
+ * dbus interface.
+ */
+G_DEFINE_TYPE (McdService, mcd_service, MCD_TYPE_MASTER);
+
+/* Private */
+
+typedef struct _McdServicePrivate
+{
+ McdPresenceFrame *presence_frame;
+ McdDispatcher *dispatcher;
+
+ McStatus last_status;
+
+ gboolean is_disposed;
+} McdServicePrivate;
+
+#define MC_EMIT_ERROR_ASYNC(mi, err) \
+ g_assert (err != NULL); \
+ dbus_g_method_return_error (mi, err); \
+ g_warning ("%s: Returning async error '%s'", G_STRFUNC, err->message); \
+ g_error_free (err);
+
+#define MC_SHOW_ERROR(err) \
+ g_assert ((err) != NULL); \
+ g_warning ("%s: Returning error '%s'", G_STRFUNC, (err)->message);
+
+/* Dbus interface implementation */
+static gboolean
+mcd_service_set_presence (GObject * obj, gint presence, gchar * message,
+ GError ** error)
+{
+ mcd_master_request_presence (MCD_MASTER (obj), presence, message);
+ return TRUE;
+}
+
+static gboolean
+mcd_service_get_presence (GObject *obj, gint *ret, GError **error)
+{
+ *ret = mcd_master_get_requested_presence (MCD_MASTER (obj));
+ return TRUE;
+}
+
+static gboolean
+mcd_service_get_presence_actual (GObject *obj, gint *ret, GError **error)
+{
+ *ret = mcd_master_get_actual_presence (MCD_MASTER (obj));
+ return TRUE;
+}
+
+static void
+mcd_service_connect_all_with_default_presence (GObject * obj,
+ DBusGMethodInvocation *mi)
+{
+ gchar *sender = dbus_g_method_get_sender (mi);
+ mcd_master_set_default_presence (MCD_MASTER (obj), sender);
+ g_free (sender);
+ dbus_g_method_return (mi);
+}
+
+static gboolean
+mcd_service_get_connection_status (GObject * obj, gchar * account_name,
+ guint * ret, GError ** error)
+{
+ *ret = mcd_master_get_account_status (MCD_MASTER (obj), account_name);
+ return TRUE;
+}
+
+static gboolean
+mcd_service_get_online_connections (GObject * obj,
+ gchar *** ret, GError ** error)
+{
+ return mcd_master_get_online_connection_names (MCD_MASTER (obj), ret);
+}
+
+static gboolean
+mcd_service_get_connection (GObject * obj, const gchar * account_name,
+ gchar ** ret_servname,
+ gchar ** ret_objpath, GError ** error)
+{
+ return mcd_master_get_account_connection_details (MCD_MASTER (obj),
+ account_name,
+ ret_servname,
+ ret_objpath);
+}
+
+static void
+mcd_service_request_channel (GObject * obj,
+ const gchar * account_name,
+ const gchar * type,
+ guint handle,
+ gint handle_type,
+ guint serial,
+ DBusGMethodInvocation *mi)
+{
+ struct mcd_channel_request req;
+ GError *err = NULL;
+
+ memset (&req, 0, sizeof (req));
+ req.account_name = account_name;
+ req.channel_type = type;
+ req.channel_handle = handle;
+ req.channel_handle_type = handle_type;
+ req.requestor_serial = serial;
+ req.requestor_client_id = dbus_g_method_get_sender (mi);
+ if (!mcd_master_request_channel (MCD_MASTER (obj), &req, &err))
+ {
+ g_free ((gchar *)req.requestor_client_id);
+ MC_EMIT_ERROR_ASYNC (mi, err);
+ return;
+ }
+ g_free ((gchar *)req.requestor_client_id);
+ dbus_g_method_return (mi);
+}
+
+static void
+mcd_service_request_channel_with_string_handle (GObject * obj,
+ const gchar * account_name,
+ const gchar * type,
+ const gchar * handle,
+ gint handle_type,
+ guint serial,
+ DBusGMethodInvocation *mi)
+{
+ struct mcd_channel_request req;
+ GError *err = NULL;
+
+ memset (&req, 0, sizeof (req));
+ req.account_name = account_name;
+ req.channel_type = type;
+ req.channel_handle_string = handle;
+ req.channel_handle_type = handle_type;
+ req.requestor_serial = serial;
+ req.requestor_client_id = dbus_g_method_get_sender (mi);
+ mcd_controller_cancel_shutdown (MCD_CONTROLLER (obj));
+ if (!mcd_master_request_channel (MCD_MASTER (obj), &req, &err))
+ {
+ g_free ((gchar *)req.requestor_client_id);
+ MC_EMIT_ERROR_ASYNC (mi, err);
+ return;
+ }
+ g_free ((gchar *)req.requestor_client_id);
+ dbus_g_method_return (mi);
+}
+
+static void
+mcd_service_cancel_channel_request (GObject * obj, guint operation_id,
+ DBusGMethodInvocation *mi)
+{
+ GError *err = NULL;
+ gchar *sender = dbus_g_method_get_sender (mi);
+ g_debug ("%s (%u)", G_STRFUNC, operation_id);
+ if (!mcd_master_cancel_channel_request (MCD_MASTER (obj), operation_id,
+ sender, &err))
+ {
+ g_warning ("%s: channel not found", G_STRFUNC);
+ g_free (sender);
+ dbus_g_method_return (mi);
+ return;
+ }
+ g_free (sender);
+ if (err)
+ {
+ MC_EMIT_ERROR_ASYNC (mi, err);
+ return;
+ }
+ dbus_g_method_return (mi);
+}
+
+static gboolean
+mcd_service_get_used_channels_count (GObject * obj, const gchar *chan_type,
+ guint * ret, GError ** error)
+{
+ if (!mcd_master_get_used_channels_count (MCD_MASTER (obj),
+ g_quark_from_string (chan_type),
+ ret, error))
+ {
+ MC_SHOW_ERROR (*error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+mcd_service_get_account_for_connection(GObject *obj,
+ const gchar *object_path,
+ gchar **ret_unique_name,
+ GError **error)
+{
+ g_debug ("%s: object_path = %s", __FUNCTION__, object_path);
+
+ if (!mcd_master_get_account_for_connection (MCD_MASTER (obj),
+ object_path,
+ ret_unique_name,
+ error))
+ {
+ MC_SHOW_ERROR (*error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+mcd_service_get_current_status(GObject *obj,
+ McStatus *status, McPresence *presence,
+ McPresence *requested_presence,
+ GPtrArray **accounts, GError **error)
+{
+ McdServicePrivate *priv = MCD_OBJECT_PRIV (obj);
+ GList *account_list, *account_node;
+ GType type;
+
+ *status = priv->last_status;
+ *presence = mcd_master_get_actual_presence (MCD_MASTER (obj));
+ *requested_presence = mcd_master_get_requested_presence (MCD_MASTER (obj));
+ *accounts = g_ptr_array_new ();
+
+ type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT,
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
+ account_list = mc_accounts_list_by_enabled (TRUE);
+ for (account_node = account_list; account_node != NULL;
+ account_node = g_list_next (account_node))
+ {
+ McAccount *account = account_node->data;
+ GValue account_data = { 0, };
+ const gchar *name;
+ TelepathyConnectionStatus status;
+ TelepathyConnectionStatusReason reason;
+ McPresence presence;
+
+ name = mc_account_get_unique_name (account);
+ status = mcd_presence_frame_get_account_status (priv->presence_frame,
+ account);
+ presence =
+ mcd_presence_frame_get_account_presence (priv->presence_frame,
+ account);
+ reason =
+ mcd_presence_frame_get_account_status_reason (priv->presence_frame,
+ account);
+
+ g_value_init (&account_data, type);
+ g_value_take_boxed (&account_data,
+ dbus_g_type_specialized_construct (type));
+ dbus_g_type_struct_set (&account_data,
+ 0, name,
+ 1, status,
+ 2, presence,
+ 3, reason,
+ G_MAXUINT);
+
+ g_ptr_array_add (*accounts, g_value_get_boxed (&account_data));
+ }
+ mc_accounts_list_free (account_list);
+ return TRUE;
+}
+
+static void
+mcd_service_remote_avatar_changed(GObject *obj,
+ const gchar *object_path,
+ guint contact_id,
+ const gchar *token,
+ DBusGMethodInvocation *mi)
+{
+ McdConnection *connection;
+ GError *error = NULL;
+
+ g_debug ("%s: object_path = %s, id = %u, token = %s", __FUNCTION__,
+ object_path, contact_id, token);
+
+ connection = mcd_master_get_connection (MCD_MASTER (obj),
+ object_path, &error);
+ if (!connection)
+ {
+ MC_EMIT_ERROR_ASYNC (mi, error);
+ return;
+ }
+ /* let the D-Bus call return immediately, there's no need for the caller to
+ * be blocked while we get the avatar */
+ dbus_g_method_return (mi);
+
+ mcd_connection_remote_avatar_changed (connection, contact_id, token);
+}
+
+#include "mcd-service-gen.h"
+
+static void
+mcd_register_dbus_object (McdService * obj)
+{
+ DBusError error;
+ DBusGConnection *connection;
+
+ g_object_get (obj, "dbus-connection", &connection, NULL);
+
+ dbus_error_init (&error);
+
+ g_debug ("Requesting MC dbus service");
+
+ dbus_bus_request_name (dbus_g_connection_get_connection (connection),
+ MISSION_CONTROL_DBUS_SERVICE, 0, &error);
+ if (dbus_error_is_set (&error))
+ {
+ g_error ("Service name '%s' is already in use - request failed",
+ MISSION_CONTROL_DBUS_SERVICE);
+ dbus_error_free (&error);
+ }
+
+ g_debug ("Registering MC object");
+ mcd_debug_print_tree (obj);
+ dbus_g_connection_register_g_object (connection,
+ MISSION_CONTROL_DBUS_OBJECT,
+ G_OBJECT (obj));
+ g_debug ("Registered MC object");
+ mcd_debug_print_tree (obj);
+}
+
+static void
+_on_account_status_changed (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ TelepathyConnectionStatus connection_status,
+ TelepathyConnectionStatusReason connection_reason,
+ McdService * obj)
+{
+ McPresence presence =
+ mcd_presence_frame_get_account_presence (presence_frame, account);
+
+ /* FIXME: Don't emit the CONNECTING state. The ui doesn handle it
+ * correctly yet.
+ */
+ if (connection_status != TP_CONN_STATUS_CONNECTING)
+ {
+ /* Emit the AccountStatusChanged signal */
+ g_debug ("Emitting account status changed for %s: status = %d, reason = %d",
+ mc_account_get_unique_name (account), connection_status,
+ connection_reason);
+
+ g_signal_emit_by_name (G_OBJECT (obj),
+ "account-status-changed", connection_status,
+ presence,
+ connection_reason,
+ mc_account_get_unique_name (account));
+ }
+}
+
+static void
+_on_account_presence_changed (McdPresenceFrame * presence_frame,
+ McAccount * account,
+ McPresence presence,
+ gchar * presence_message, McdService * obj)
+{
+ /* Emit the AccountStatusChanged signal */
+ g_debug ("Emitting presence changed for %s: presence = %d, message = %s",
+ mc_account_get_unique_name (account), presence,
+ presence_message);
+
+ g_signal_emit_by_name (G_OBJECT (obj),
+ "account-status-changed",
+ mcd_presence_frame_get_account_status
+ (presence_frame, account), presence,
+ mcd_presence_frame_get_account_status_reason
+ (presence_frame, account),
+ mc_account_get_unique_name (account));
+}
+
+static void
+_on_presence_requested (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ gchar * presence_message, McdService * obj)
+{
+ /* Begin shutdown if it is offline request */
+ if (presence == MC_PRESENCE_OFFLINE ||
+ presence == MC_PRESENCE_UNSET)
+ mcd_controller_shutdown (MCD_CONTROLLER (obj),
+ "Offline presence requested");
+ else
+ /* If there is a presence request, make sure shutdown is canceled */
+ mcd_controller_cancel_shutdown (MCD_CONTROLLER (obj));
+
+ /* Emit the AccountStatusChanged signal */
+ g_signal_emit_by_name (G_OBJECT (obj),
+ "presence-status-requested", presence);
+}
+
+static void
+_on_presence_actual (McdPresenceFrame * presence_frame,
+ McPresence presence,
+ gchar * presence_message, McdService * obj)
+{
+ /* Emit the AccountStatusChanged signal */
+ g_signal_emit_by_name (G_OBJECT (obj), "presence-status-actual", presence);
+}
+
+static void
+count_connections (McdOperation *manager, guint *connections)
+{
+ *connections += g_list_length ((GList *)
+ mcd_operation_get_missions (manager));
+}
+
+static void
+_on_status_actual (McdPresenceFrame * presence_frame,
+ TelepathyConnectionStatus status,
+ McdService * obj)
+{
+ /* Everyone just got disconnected */
+ if (status == TP_CONN_STATUS_DISCONNECTED)
+ {
+ guint connections = 0;
+ /* if there are no connections, then exit. Count the connections
+ * regardless of their status: we are supposing that if a connection is
+ * still there, then there is a good reason for it and we won't exit,
+ * even if it's not active (it might be trying to reconnect) */
+ mcd_operation_foreach (MCD_OPERATION (obj), (GFunc)count_connections,
+ &connections);
+ if (connections == 0)
+ mcd_controller_shutdown (MCD_CONTROLLER (obj), "No connections");
+ }
+}
+
+static void
+mcd_service_disconnect (McdMission *mission)
+{
+ MCD_MISSION_CLASS (mcd_service_parent_class)->disconnect (mission);
+ mcd_controller_shutdown (MCD_CONTROLLER (mission), "Disconnected");
+}
+
+static void
+_on_presence_stable (McdPresenceFrame *presence_frame, gboolean is_stable,
+ McdService *service)
+{
+ McdServicePrivate *priv = MCD_OBJECT_PRIV (service);
+ McPresence req_presence;
+ McStatus status;
+
+ req_presence = mcd_presence_frame_get_requested_presence (presence_frame);
+ if (is_stable)
+ {
+ if (mcd_presence_frame_get_actual_presence (presence_frame) >=
+ MC_PRESENCE_AVAILABLE)
+ status = MC_STATUS_CONNECTED;
+ else
+ status = MC_STATUS_DISCONNECTED;
+ }
+ else
+ status = MC_STATUS_CONNECTING;
+
+ if (status != priv->last_status)
+ {
+ g_signal_emit (service, signals[STATUS_ACTUAL], 0, status,
+ req_presence);
+ priv->last_status = status;
+ }
+}
+
+static void
+_on_dispatcher_channel_added (McdDispatcher *dispatcher,
+ McdChannel *channel, McdService *obj)
+{
+ /* Nothing to do for now */
+}
+
+static void
+_on_dispatcher_channel_removed (McdDispatcher *dispatcher,
+ McdChannel *channel, McdService *obj)
+{
+ const gchar *chan_type;
+ GQuark chan_type_quark;
+ gint usage;
+
+ chan_type = mcd_channel_get_channel_type (channel);
+ chan_type_quark = mcd_channel_get_channel_type_quark (channel);
+ usage = mcd_dispatcher_get_channel_type_usage (dispatcher,
+ chan_type_quark);
+
+ /* Signal that the channel count has changed */
+ g_signal_emit_by_name (G_OBJECT (obj),
+ "used-channels-count-changed",
+ chan_type, usage);
+}
+
+static void
+_on_dispatcher_channel_dispatched (McdDispatcher *dispatcher,
+ McdChannel *channel,
+ McdService *obj)
+{
+ const gchar *chan_type;
+ GQuark chan_type_quark;
+ gint usage;
+
+ chan_type = mcd_channel_get_channel_type (channel);
+ chan_type_quark = mcd_channel_get_channel_type_quark (channel);
+ usage = mcd_dispatcher_get_channel_type_usage (dispatcher,
+ chan_type_quark);
+
+ /* Signal that the channel count has changed */
+ g_signal_emit_by_name (G_OBJECT (obj),
+ "used-channels-count-changed",
+ chan_type, usage);
+}
+
+static void
+_on_dispatcher_channel_dispatch_failed (McdDispatcher *dispatcher,
+ McdChannel *channel, GError *error,
+ McdService *obj)
+{
+ guint requestor_serial;
+ gchar *requestor_client_id;
+
+ g_debug ("%s", G_STRFUNC);
+ g_object_get (channel, "requestor-serial", &requestor_serial,
+ "requestor-client-id", &requestor_client_id, NULL);
+
+ if (requestor_client_id)
+ {
+ g_signal_emit_by_name (obj, "mcd-error", requestor_serial,
+ requestor_client_id, error->code);
+ g_free (requestor_client_id);
+ }
+
+ g_debug ("MC ERROR (channel request): %s", error->message);
+}
+
+static void
+mcd_dispose (GObject * obj)
+{
+ McdServicePrivate *priv;
+ McdService *self = MCD_OBJECT (obj);
+
+ priv = MCD_OBJECT_PRIV (self);
+
+ if (priv->is_disposed)
+ {
+ return;
+ }
+
+ priv->is_disposed = TRUE;
+
+ if (priv->presence_frame)
+ {
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ _on_account_status_changed,
+ self);
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ _on_account_presence_changed,
+ self);
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ _on_presence_requested, self);
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ _on_presence_actual, self);
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ _on_status_actual, self);
+ g_signal_handlers_disconnect_by_func (priv->presence_frame,
+ _on_presence_stable, self);
+ g_object_unref (priv->presence_frame);
+ }
+
+ if (priv->dispatcher)
+ {
+ g_signal_handlers_disconnect_by_func (priv->dispatcher,
+ _on_dispatcher_channel_added,
+ self);
+ g_signal_handlers_disconnect_by_func (priv->dispatcher,
+ _on_dispatcher_channel_removed,
+ self);
+ g_signal_handlers_disconnect_by_func (priv->dispatcher,
+ _on_dispatcher_channel_dispatched,
+ self);
+ g_signal_handlers_disconnect_by_func (priv->dispatcher,
+ _on_dispatcher_channel_dispatch_failed,
+ self);
+ g_object_unref (priv->dispatcher);
+ }
+
+ if (self->main_loop)
+ {
+ g_main_loop_quit (self->main_loop);
+ g_main_loop_unref (self->main_loop);
+ self->main_loop = NULL;
+ }
+
+ if (G_OBJECT_CLASS (parent_class)->dispose)
+ {
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+ }
+}
+
+static void
+mcd_service_init (McdService * obj)
+{
+ McdServicePrivate *priv = MCD_OBJECT_PRIV (obj);
+
+ obj->main_loop = g_main_loop_new (NULL, FALSE);
+
+ priv->last_status = -1;
+
+ g_object_get (obj,
+ "presence-frame", &priv->presence_frame,
+ "dispatcher", &priv->dispatcher, NULL);
+
+ /* Setup presence signals */
+ g_signal_connect (priv->presence_frame, "status-changed",
+ G_CALLBACK (_on_account_status_changed), obj);
+ g_signal_connect (priv->presence_frame, "presence-changed",
+ G_CALLBACK (_on_account_presence_changed), obj);
+ g_signal_connect (priv->presence_frame, "presence-requested",
+ G_CALLBACK (_on_presence_requested), obj);
+ g_signal_connect (priv->presence_frame, "presence-actual",
+ G_CALLBACK (_on_presence_actual), obj);
+ g_signal_connect (priv->presence_frame, "status-actual",
+ G_CALLBACK (_on_status_actual), obj);
+ g_signal_connect (priv->presence_frame, "presence-stable",
+ G_CALLBACK (_on_presence_stable), obj);
+
+ /* Setup dispatcher signals */
+ g_signal_connect (priv->dispatcher, "channel-added",
+ G_CALLBACK (_on_dispatcher_channel_added), obj);
+ g_signal_connect (priv->dispatcher, "channel-removed",
+ G_CALLBACK (_on_dispatcher_channel_removed), obj);
+ g_signal_connect (priv->dispatcher, "dispatched",
+ G_CALLBACK (_on_dispatcher_channel_dispatched), obj);
+ g_signal_connect (priv->dispatcher, "dispatch-failed",
+ G_CALLBACK (_on_dispatcher_channel_dispatch_failed), obj);
+
+ mcd_register_dbus_object (obj);
+ mcd_debug_print_tree (obj);
+}
+
+static void
+mcd_service_class_init (McdServiceClass * self)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (self);
+ McdMissionClass *mission_class = MCD_MISSION_CLASS (self);
+
+ parent_class = g_type_class_peek_parent (self);
+ gobject_class->dispose = mcd_dispose;
+ mission_class->disconnect = mcd_service_disconnect;
+
+ g_type_class_add_private (gobject_class, sizeof (McdServicePrivate));
+
+ /* AccountStatusChanged signal */
+ signals[ACCOUNT_STATUS_CHANGED] =
+ g_signal_new ("account-status-changed",
+ G_OBJECT_CLASS_TYPE (self),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, mcd_marshal_VOID__UINT_UINT_UINT_STRING,
+ G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_UINT,
+ G_TYPE_UINT, G_TYPE_STRING);
+ /* libmc request_error signal */
+ signals[ERROR] =
+ g_signal_new ("mcd-error",
+ G_OBJECT_CLASS_TYPE (self),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, mcd_marshal_VOID__UINT_STRING_UINT, G_TYPE_NONE,
+ 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT);
+ /* PresenceStatusRequested signal */
+ g_signal_new ("presence-status-requested",
+ G_OBJECT_CLASS_TYPE (self),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, mcd_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ /* PresenceStatusActual signal */
+ g_signal_new ("presence-status-actual",
+ G_OBJECT_CLASS_TYPE (self),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, mcd_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ /* UsedChannelsCountChanged signal */
+ signals[USED_CHANNELS_COUNT_CHANGED] =
+ g_signal_new ("used-channels-count-changed",
+ G_OBJECT_CLASS_TYPE (self),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, mcd_marshal_VOID__STRING_UINT,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
+ /* StatusActual signal */
+ signals[STATUS_ACTUAL] =
+ g_signal_new ("status-actual",
+ G_OBJECT_CLASS_TYPE (self),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, mcd_marshal_VOID__UINT_UINT,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
+ dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (self),
+ &dbus_glib_mcd_service_object_info);
+}
+
+McdService *
+mcd_service_new (void)
+{
+ McdService *obj;
+ obj = g_object_new (MCD_TYPE_SERVICE, NULL);
+ return obj;
+}
+
+void
+mcd_service_run (McdService * self)
+{
+ g_main_loop_run (self->main_loop);
+}
+
+/* FIXME: This is defined twice. The other definition is in
+ * libmissioncontrol/mission-control.c
+ */
+GQuark
+mission_control_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (quark == 0)
+ quark = g_quark_from_static_string ("mission-control-quark");
+ return quark;
+}
+
diff --git a/src/mcd-service.h b/src/mcd-service.h
new file mode 100644
index 00000000..327e78f9
--- /dev/null
+++ b/src/mcd-service.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_OBJECT_H
+#define MCD_OBJECT_H
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+#include "mcd-master.h"
+
+#define MCD_TYPE_SERVICE (mcd_service_get_type ())
+
+#define MCD_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), MCD_TYPE_SERVICE, \
+ McdService))
+
+#define MCD_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST \
+ ((klass), MCD_TYPE_SERVICE, \
+ McdServiceClass))
+
+#define MCD_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), MCD_TYPE_SERVICE))
+
+#define MCD_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE \
+ ((klass), MCD_TYPE_SERVICE))
+
+#define MCD_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), MCD_TYPE_SERVICE, \
+ McdServiceClass))
+
+typedef struct _McdService McdService;
+typedef struct _McdServiceClass McdServiceClass;
+
+struct _McdServiceClass
+{
+ McdMasterClass parent_class;
+};
+
+
+struct _McdService
+{
+ McdMaster parent;
+ GMainLoop *main_loop;
+};
+
+GType mcd_service_get_type (void);
+
+McdService *mcd_service_new (void);
+void mcd_service_run (McdService * self);
+
+#endif
diff --git a/src/mcd-signals-marshal.list b/src/mcd-signals-marshal.list
new file mode 100644
index 00000000..4ed420f3
--- /dev/null
+++ b/src/mcd-signals-marshal.list
@@ -0,0 +1,15 @@
+VOID:UINT,UINT,UINT,STRING
+VOID:UINT,STRING,UINT
+VOID:STRING,UINT
+VOID:UINT
+VOID:UINT,UINT
+VOID:OBJECT,ENUM,STRING
+VOID:ENUM,STRING
+VOID:OBJECT,ENUM,ENUM
+VOID:INT,STRING
+VOID:INT
+VOID:OBJECT,INT,STRING
+VOID:OBJECT,INT,INT
+VOID:OBJECT
+VOID:OBJECT,POINTER
+VOID:BOOLEAN
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 00000000..37fd44c7
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES = $(DBUS_CFLAGS) $(TELEPATHY_CFLAGS) -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ -DMC_DISABLE_DEPRECATED \
+ -DLIBDIR="@libdir@" -DLIBVERSION="0"
+
+if HAVE_TESTS
+
+bin_PROGRAMS = mc-client
+mc_client_SOURCES = mc-client.c
+mc_client_LDADD = $(top_srcdir)/libmissioncontrol/libmissioncontrol.la
+
+endif
diff --git a/test/mc-client.c b/test/mc-client.c
new file mode 100644
index 00000000..42dac402
--- /dev/null
+++ b/test/mc-client.c
@@ -0,0 +1,83 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * This file is part of mission-control
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Naba Kumar <naba.kumar@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+#include "libmissioncontrol/mission-control.h"
+
+
+static void
+on_service_ended (MissionControl *mc)
+{
+ g_debug ("Mission control has ended");
+}
+
+static void
+account_status_changed_cb (GObject *object,
+ TelepathyConnectionStatus status,
+ McPresence presence,
+ TelepathyConnectionStatusReason reason,
+ const gchar *account,
+ gpointer data)
+{
+ g_debug ("Account status changed: %s, status = %u, presence = %u, reason = %u",
+ account, status, presence, reason);
+}
+
+static void mc_callback (MissionControl *mc, GError *error, gpointer data)
+{
+ if (error)
+ {
+ g_debug ("%s: got error code %u (%s), data is %p", G_STRFUNC,
+ error->code, error->message, data);
+ g_error_free (error);
+ }
+ else
+ g_debug ("%s: data is %p", G_STRFUNC, data);
+}
+
+int main ()
+{
+ MissionControl *mc;
+ DBusGConnection *dbus_conn = NULL;
+ GMainLoop *main_loop;
+
+ g_type_init ();
+ dbus_conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+
+ mc = mission_control_new (dbus_conn);
+ g_signal_connect (mc, "ServiceEnded", G_CALLBACK (on_service_ended), NULL);
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (mc),
+ "AccountStatusChanged",
+ G_CALLBACK (account_status_changed_cb),
+ NULL, NULL); /* NULL is for a DestroyNotify */
+
+ mission_control_connect_all_with_default_presence (mc, mc_callback, NULL);
+ main_loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (main_loop);
+
+ return 0;
+}
+
+
diff --git a/xml/Makefile.am b/xml/Makefile.am
new file mode 100644
index 00000000..92dca715
--- /dev/null
+++ b/xml/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = mcd-dbus-services.xml
diff --git a/xml/mcd-dbus-services.xml b/xml/mcd-dbus-services.xml
new file mode 100644
index 00000000..0e8ebc9e
--- /dev/null
+++ b/xml/mcd-dbus-services.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/freedesktop/Telepathy/MissionControl">
+ <interface name="org.freedesktop.Telepathy.MissionControl">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="mcd_service"/>
+ <annotation name="org.freedesktop.DBus.GLib.ClientCSymbol"
+ value="mission_control_dbus"/>
+ <method name="SetPresence">
+ <arg type="u" name="presence" direction="in" />
+ <arg type="s" name="message" direction="in" />
+ </method>
+ <method name="GetPresence">
+ <arg type="u" direction="out" />
+ </method>
+ <method name="GetPresenceActual">
+ <arg type="u" direction="out" />
+ </method>
+ <method name="RequestChannel">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg type="s" name="account_name" direction="in" />
+ <arg type="s" name="type" direction="in" />
+ <arg type="u" name="handle" direction="in" />
+ <arg type="i" name="handle_type" direction="in" />
+ <arg type="u" name="serial" direction="in" />
+ </method>
+ <method name="RequestChannelWithStringHandle">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg type="s" name="account_name" direction="in" />
+ <arg type="s" name="type" direction="in" />
+ <arg type="s" name="handle" direction="in" />
+ <arg type="i" name="handle_type" direction="in" />
+ <arg type="u" name="serial" direction="in" />
+ </method>
+ <method name="CancelChannelRequest">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg type="u" name="operation_id" direction="in" />
+ </method>
+ <method name="ConnectAllWithDefaultPresence">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
+ <method name="GetConnectionStatus">
+ <arg type="s" name="account_name" direction="in" />
+ <arg type="u" direction="out" />
+ </method>
+ <method name="GetOnlineConnections">
+ <arg type="as" direction="out" />
+ </method>
+ <method name="GetConnection">
+ <arg type="s" name="account_name" direction="in" />
+ <arg type="s" direction="out" />
+ <arg type="o" direction="out" />
+ </method>
+ <method name="GetAccountForConnection">
+ <arg type="s" direction="out" />
+ <arg type="s" name="object_path" direction="in" />
+ </method>
+ <method name="GetUsedChannelsCount">
+ <arg type="u" direction="out" />
+ <arg type="s" name="type" direction="in" />
+ </method>
+ <method name="GetCurrentStatus">
+ <arg type="u" name="status" direction="out" />
+ <arg type="u" name="presence" direction="out" />
+ <arg type="u" name="requested_presence" direction="out" />
+ <arg type="a(suuu)" name="accounts" direction="out" />
+ </method>
+ <method name="RemoteAvatarChanged">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg type="s" name="object_path" direction="in" />
+ <arg type="u" name="contact_id" direction="in" />
+ <arg type="s" name="token" direction="in" />
+ </method>
+ <signal name="AccountStatusChanged">
+ <arg type="u" name="status" />
+ <arg type="u" name="presence" />
+ <arg type="u" name="reason" />
+ <arg type="s" name="account_id" />
+ </signal>
+ <signal name="McdError">
+ <arg type="u" name="serial" />
+ <arg type="s" name="client_id" />
+ <arg type="u" name="error_id" />
+ </signal>
+ <signal name="PresenceStatusRequested">
+ <arg type="u" name="presence" />
+ </signal>
+ <signal name="PresenceStatusActual">
+ <arg type="u" name="presence" />
+ </signal>
+ <signal name="UsedChannelsCountChanged">
+ <arg type="s" name="type" />
+ <arg type="u" name="count" />
+ </signal>
+ <signal name="StatusActual">
+ <arg type="u" name="status" />
+ <arg type="u" name="presence" />
+ </signal>
+ </interface>
+</node>