network-manager-pptp r2 - in trunk: . auth-dialog common-gnome doc po properties src



Author: dcbw
Date: Thu Dec 11 19:53:06 2008
New Revision: 2
URL: http://svn.gnome.org/viewvc/network-manager-pptp?rev=2&view=rev

Log:
2008-12-11  Dan Williams  <dcbw redhat com>

	* Split into separate repository



Added:
   trunk/AUTHORS
   trunk/COPYING
   trunk/ChangeLog
   trunk/INSTALL
   trunk/MAINTAINERS
   trunk/Makefile.am
   trunk/NEWS
   trunk/README
   trunk/TODO
   trunk/auth-dialog/
   trunk/auth-dialog/.cvsignore
   trunk/auth-dialog/Makefile.am
   trunk/auth-dialog/gnome-two-password-dialog.c
   trunk/auth-dialog/gnome-two-password-dialog.h
   trunk/auth-dialog/main.c
   trunk/autogen.sh   (contents, props changed)
   trunk/common-gnome/
   trunk/common-gnome/Makefile.am
   trunk/common-gnome/keyring-helpers.c
   trunk/common-gnome/keyring-helpers.h
   trunk/configure.in
   trunk/doc/
   trunk/doc/example-pptp-system-wide-connection.sh   (contents, props changed)
   trunk/gnome-mime-application-x-pptp-settings.png   (contents, props changed)
   trunk/nm-pptp-service.conf
   trunk/nm-pptp-service.name.in
   trunk/nm-pptp.desktop.in
   trunk/po/
   trunk/po/.cvsignore
   trunk/po/ChangeLog
   trunk/po/LINGUAS
   trunk/po/POTFILES.in
   trunk/po/ar.po
   trunk/po/be latin po
   trunk/po/bg.po
   trunk/po/ca.po
   trunk/po/cs.po
   trunk/po/da.po
   trunk/po/de.po
   trunk/po/dz.po
   trunk/po/el.po
   trunk/po/en_GB.po
   trunk/po/es.po
   trunk/po/et.po
   trunk/po/eu.po
   trunk/po/fi.po
   trunk/po/fr.po
   trunk/po/gl.po
   trunk/po/he.po
   trunk/po/hu.po
   trunk/po/it.po
   trunk/po/ja.po
   trunk/po/ka.po
   trunk/po/ko.po
   trunk/po/lt.po
   trunk/po/mk.po
   trunk/po/nb.po
   trunk/po/nl.po
   trunk/po/pa.po
   trunk/po/pl.po
   trunk/po/pt.po
   trunk/po/pt_BR.po
   trunk/po/ru.po
   trunk/po/sv.po
   trunk/po/th.po
   trunk/po/uk.po
   trunk/po/vi.po
   trunk/po/zh_CN.po
   trunk/po/zh_HK.po
   trunk/po/zh_TW.po
   trunk/properties/
   trunk/properties/.cvsignore
   trunk/properties/Makefile.am
   trunk/properties/advanced-dialog.c
   trunk/properties/advanced-dialog.h
   trunk/properties/import-export.c
   trunk/properties/import-export.h
   trunk/properties/nm-pptp-dialog.glade
   trunk/properties/nm-pptp.c
   trunk/properties/nm-pptp.h
   trunk/src/
   trunk/src/.cvsignore
   trunk/src/Makefile.am
   trunk/src/nm-ppp-status.h
   trunk/src/nm-pptp-pppd-plugin.c
   trunk/src/nm-pptp-pppd-service.xml
   trunk/src/nm-pptp-service.c
   trunk/src/nm-pptp-service.h

Added: trunk/AUTHORS
==============================================================================
--- (empty file)
+++ trunk/AUTHORS	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,4 @@
+Antony Mee <eemynotna gmail com>
+Tim Niemueller <tim niemueller de>
+Dan Williams <dcbw redhat com>
+

Added: trunk/COPYING
==============================================================================
--- (empty file)
+++ trunk/COPYING	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) 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; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, 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 executable.  However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+  5. 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 Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+  7. 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 Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  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 program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; 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.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: trunk/INSTALL
==============================================================================
--- (empty file)
+++ trunk/INSTALL	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,229 @@
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+   This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+

Added: trunk/MAINTAINERS
==============================================================================
--- (empty file)
+++ trunk/MAINTAINERS	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,4 @@
+Dan Williams
+E-mail: dcbw redhat com
+Userid: dcbw
+

Added: trunk/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/Makefile.am	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,37 @@
+AUTOMAKE_OPTIONS = foreign
+
+if WITH_GNOME
+SUBDIRS = src common-gnome auth-dialog properties po
+else
+SUBDIRS = src
+endif
+
+dbusservicedir = $(sysconfdir)/dbus-1/system.d
+dbusservice_DATA = nm-pptp-service.conf
+
+nmvpnservicedir = $(sysconfdir)/NetworkManager/VPN
+nmvpnservice_DATA = nm-pptp-service.name
+
+if WITH_GNOME
+desktopdir = $(datadir)/applications
+desktop_in_files = nm-pptp.desktop.in
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+ INTLTOOL_DESKTOP_RULE@
+
+icondir = $(datadir)/icons/hicolor/48x48/apps
+icon_DATA = gnome-mime-application-x-pptp-settings.png
+endif
+
+nm-pptp-service.name: $(srcdir)/nm-pptp-service.name.in
+	sed -e 's|[ ]LIBEXECDIR[@]|$(libexecdir)|g' $< >$@
+
+EXTRA_DIST = nm-pptp-service.name.in \
+             $(dbusservice_DATA)  \
+             $(desktop_in_files)  \
+             $(icon_DATA)         \
+             intltool-extract.in  \
+             intltool-merge.in    \
+             intltool-update.in
+
+CLEANFILES = $(nmvpnservice_DATA) $(desktop_DATA) *~
+DISTCLEANFILES = intltool-extract intltool-merge intltool-update

Added: trunk/NEWS
==============================================================================

Added: trunk/README
==============================================================================
--- (empty file)
+++ trunk/README	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,17 @@
+PPTP support for NetworkManager
+
+This requires the Linux PPTP client installed 
+http://pptpclient.sourceforge.net/
+
+0.7.x version:
+(C) 2008 Dan Williams <dcbw redhat com>, and Tambet Ingo <tambet gmail com>
+
+0.6.x version:
+(C) 2005 - 2007 Antony Mee   http://www.students.ncl.ac.uk/a.j.mee
+Based entirely on OpenVPN support by Tim Niemueller http://www.niemueller.de
+
+
+Theory of operation
+------------------------------
+
+

Added: trunk/TODO
==============================================================================
--- (empty file)
+++ trunk/TODO	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,147 @@
+Future plans are currently hanging on what people want out of this.
+It appears 
+
+    ^^^^^ ROAD MAP ^^^^^
+
+\/\/\/  CURRENT VERSION \/\/\/
+
+Version 0.7.0-beta
+------------------
+
+   * Renamed/relabled things to be consistent with a general PPPd service
+   * Total revamp of the configuration interface
+        - More abstract.  Seperated the dialog (glade) details
+          from behaviour considerable.  Implementation now simply
+          requires a glade file and a few lines of rather declarative
+          code.
+   * Add configuration options to select alternative ptys
+        - though only PPTP is actually defined at the moment
+        - Dial-up has been put in to the configuration as a 
+            "feature preview" but it doesn't actually do anything
+            at present.
+   * Runs pppd asynchronously (allows pppd to fork)
+   * Crash on disconnect fixed.
+   * Added "debug mode" to show more detailed output.
+
+Bugs:
+   * Does not seem to remember you login information even if
+     told to do so. (FIXED)
+   * Still only support for CHAP authentication.
+
+
+Version 0.6.9
+--------------------------------
+
+Bugs:
+  * Possible NetworkManager crash on disconnect from VPN! (FIXED)
+  * Add dialog option to select different authentication methods 
+  * Add dialog options for the rest of the 'hard coded' pppd options. (FIXED)
+
+
+
+--------------------------------
+PREHISTORY
+Version 0.1.0 -> 0.5.0
+
+Hi Nikolaus,
+
+Yes, I've did quite a bit of work on it.  Infact I totally revamped it to use a pppd plugin as it's helper. (Thus is can do the DNS + routing without modifications to your local /etc/ppp files)
+
+Actually there is one exception... Many distros have an ip-up script which implements usepeerdns functionality thus replacing resolve.conf... This conflicts with NetworkManager's actions so may need to be removed. Sadly there appears to be no way to tell pppd NOT to execute /etc/ppp/ip-up if it exists!
+
+Uses a pppd plugin to handle CHAP authentication (not sure of the V2 implications...) and ip-up functionality... It explicitly resolves the IP of the vpn server before starting pppd. And starts pppd with the pty option rather than letting pptp start pppd (as recomented by the pptp maintainer).
+
+Sadly, I haven't quite figured out how I'm gonna get the username and password from the vpn-daemon to the pppd helper plugin infact I've just got my credentials hard coded in the plugin for testing!
+The reason I haven't fixed that is that there is another strange behaviour where by the pptp vpn daemon (sometimes!) takes NM down when it exits!!  It seems to seg fault but I can't find the cause. I've been really busy but  would love somone to take a look at this.  I can upload it in it's present state with instructions for where to insert your credentials if you/anyone else would be willing to try it and perhaps assist me.
+
+tOnY
+
+
+Nikolaus Filus wrote:
+
+> Hi,
+>
+> I just managed to get your pptp plugin "working" for my university setup. It was a hard piece of work, since I'm not familiar with NM or pptp details. There are several issues to be fixed and I hope this report will be usefull for you. I don't attach patches as my modifications are just hacks :)
+>
+> 1. nm-pptp-service-pptp-helper
+> The while-loop doesn't work, as I wasn't able to find a place, where
+> foreign_option_%i shall be defined. It seems to me as if this code is incomplete and you wanted to scan through the whole environment and
+> analyse the options. I had to manually add parsing of DNS, DNS1 and DNS2 which are set in my environment, or my resolv.conf is empty after connecting to the vpn.
+>
+> 2. nm-pptp-service
+> encrypt-mppe was never attached to my pppd options and I had to add
+>
+>  g_ptr_array_add (pptp_argv, (gpointer) "require-mschap-v2");
+>  g_ptr_array_add (pptp_argv, (gpointer) "mppe");
+>  g_ptr_array_add (pptp_argv, (gpointer) "required,stateless");
+>
+> outside the for-loop. As you can see, I also need the "require-mschap-v2" option. For this to work I need to specify a special remotename, which is NOT the hostname, as used in your code. This also requires a second line
+> in chap-secrets.
+>
+> 3. configuration
+> By default a new default route to ppp0 is specified, deleting the old one. I need to preserve it (by setting vpn-routes to 0.0.0.0/0) and add
+>
+>  route add -host vpn-gw dev eth1
+>  route add default dev ppp0
+>
+> manually.
+>
+>
+> With this modifications, I was able to connect the vpn at my university "using" networkmanager.
+>
+>
+> Are you working on the pppd plugin as announced on the mailinglist? I would be glad to test it :)
+>
+>
+> Thanks for your work
+>
+> Nikolaus Filus
+>
+>  
+>
+
+
+
+
+
+Dan Williams wrote:
+
+> But in your case, the pppd-vpn-service daemon could just do whatever it
+> does to start the connection, but provide a dbus service that when
+> called, returns the password and username.  The pppd plugin would then
+> call this dbus service and request the pass & user.
+>
+>  
+>
+That is precisely what I intend and started implementing it. I just wanted to fix the strange and 'intermittent' segfault before
+adding anymore complexity.
+
+I only hesitated when naming the dbus service.
+
+> There are some things to think hard about here though, namely the
+> security of it.  If you have a daemon providing a dbus service, unless
+> you lock it down anyone can call its methods.  So you'd have to make
+> sure that you lock down the dbus policy for the service-daemon pretty
+> tight.  If you restrict it to just 'root'/uid 0, any root app could ask
+> for the user and password.  But then again, any 'root' app can do
+> horrible things to your system anyway.  So this might be an acceptable
+> course of action.
+>  
+>
+I imagined that root access would be sufficient in this case too.  I suppose
+the only other way is for the vpn-daemon to pass some secret cookie to the
+pppd on start up that the plugin then uses when asking for the user/pass later
+but that too would open all kinds of security holes I suppose.
+
+Anyway... A root process could overwrite the pppd plugin in /usr/lib with
+something malicious so I can't see any possible gain.  Just as a root process could
+overwrite the vpnc binary with a script which 'tee' s the standard input to a file :-)
+
+> Ideally this could be solved upstream in pppd.  But at some point you
+> simply do best-effort to hide the username & password from view, keep
+> investigating how to do it better, and fix it a bit later.
+>  
+>
+Exactly.  "Just works" not "Will at some future time just work" right :-)
+
+tOnY 

Added: trunk/auth-dialog/.cvsignore
==============================================================================
--- (empty file)
+++ trunk/auth-dialog/.cvsignore	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,5 @@
+Makefile.in
+Makefile
+nm-ppp-auth-dialog
+.libs
+.deps

Added: trunk/auth-dialog/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/auth-dialog/Makefile.am	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,34 @@
+INCLUDES = -I${top_srcdir}
+
+libexec_PROGRAMS = nm-pptp-auth-dialog
+
+nm_pptp_auth_dialog_CPPFLAGS =			\
+	$(NM_UTILS_CFLAGS)			\
+	$(GTHREAD_CFLAGS)			\
+	$(GTK_CFLAGS)				\
+	$(LIBGNOMEUI_CFLAGS)			\
+	$(GNOMEKEYRING_CFLAGS)			\
+	-DICONDIR=\""$(datadir)/pixmaps"\"	\
+	-DGLADEDIR=\""$(gladedir)"\"		\
+	-DBINDIR=\""$(bindir)"\"		\
+	-DDBUS_API_SUBJECT_TO_CHANGE		\
+	-DG_DISABLE_DEPRECATED			\
+	-DGDK_DISABLE_DEPRECATED		\
+	-DGNOME_DISABLE_DEPRECATED		\
+	-DGNOMELOCALEDIR=\"$(datadir)/locale\"	\
+	-DVERSION=\"$(VERSION)\"			\
+	$(NULL)
+
+nm_pptp_auth_dialog_SOURCES =			\
+	main.c					\
+	gnome-two-password-dialog.c		\
+	gnome-two-password-dialog.h		\
+	$(NULL)
+
+nm_pptp_auth_dialog_LDADD =			\
+	$(GTK_LIBS)				\
+	$(LIBGNOMEUI_LIBS)			\
+	$(top_builddir)/common-gnome/libnm-pptp-common-gnome.la  \
+	$(NULL)
+
+CLEANFILES = *~

Added: trunk/auth-dialog/gnome-two-password-dialog.c
==============================================================================
--- (empty file)
+++ trunk/auth-dialog/gnome-two-password-dialog.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,743 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* gnome-password-dialog.c - A use password prompting dialog widget.
+
+   Copyright (C) 1999, 2000 Eazel, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the ree Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Authors: Ramiro Estrugo <ramiro eazel com>
+*/
+
+#include <config.h>
+//#include "gnome-i18nP.h"
+#include "gnome-two-password-dialog.h"
+#include <gtk/gtkbox.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkradiobutton.h>
+#include <gtk/gtkstock.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+
+struct GnomeTwoPasswordDialogDetails
+{
+	/* Attributes */
+	gboolean readonly_username;
+	gboolean readonly_domain;
+
+	gboolean show_username;
+	gboolean show_domain;
+	gboolean show_password;
+	gboolean show_password_secondary;
+	
+	/* TODO: */
+	gboolean remember;
+	char *remember_label_text;
+
+	/* Internal widgetry and flags */
+	GtkWidget *username_entry;
+	GtkWidget *password_entry;
+	GtkWidget *password_entry_secondary;
+	GtkWidget *domain_entry;
+
+	GtkWidget *table_alignment;
+	GtkWidget *table;
+	
+	GtkWidget *remember_session_button;
+	GtkWidget *remember_forever_button;
+
+	GtkWidget *radio_vbox;
+	GtkWidget *connect_with_no_userpass_button;
+	GtkWidget *connect_with_userpass_button;
+
+	gboolean anon_support_on;
+
+	char *secondary_password_label;
+};
+
+/* Caption table rows indices */
+static const guint CAPTION_TABLE_USERNAME_ROW = 0;
+static const guint CAPTION_TABLE_PASSWORD_ROW = 1;
+
+/* GnomeTwoPasswordDialogClass methods */
+static void gnome_two_password_dialog_class_init (GnomeTwoPasswordDialogClass *password_dialog_class);
+static void gnome_two_password_dialog_init       (GnomeTwoPasswordDialog      *password_dialog);
+
+/* GObjectClass methods */
+static void gnome_two_password_dialog_finalize         (GObject                *object);
+
+
+/* GtkDialog callbacks */
+static void dialog_show_callback                 (GtkWidget              *widget,
+						  gpointer                callback_data);
+static void dialog_close_callback                (GtkWidget              *widget,
+						  gpointer                callback_data);
+
+static gpointer parent_class;
+
+GType
+gnome_two_password_dialog_get_type (void)
+{
+	static GType type = 0;
+
+	if (!type) {
+		static const GTypeInfo info = {
+			sizeof (GnomeTwoPasswordDialogClass),
+                        NULL, NULL,
+			(GClassInitFunc) gnome_two_password_dialog_class_init,
+                        NULL, NULL,
+			sizeof (GnomeTwoPasswordDialog), 0,
+			(GInstanceInitFunc) gnome_two_password_dialog_init,
+			NULL
+		};
+
+                type = g_type_register_static (gtk_dialog_get_type(), 
+					       "GnomeTwoPasswordDialog", 
+					       &info, 0);
+
+		parent_class = g_type_class_ref (gtk_dialog_get_type());
+	}
+
+	return type;
+}
+
+
+static void
+gnome_two_password_dialog_class_init (GnomeTwoPasswordDialogClass * klass)
+{
+	G_OBJECT_CLASS (klass)->finalize = gnome_two_password_dialog_finalize;
+}
+
+static void
+gnome_two_password_dialog_init (GnomeTwoPasswordDialog *password_dialog)
+{
+	password_dialog->details = g_new0 (GnomeTwoPasswordDialogDetails, 1);
+	password_dialog->details->show_username = TRUE;
+	password_dialog->details->show_password = TRUE;
+	password_dialog->details->show_password_secondary = TRUE;
+	password_dialog->details->anon_support_on = FALSE;
+
+	password_dialog->details->secondary_password_label = g_strdup ( _("_Secondary Password:") );
+}
+
+/* GObjectClass methods */
+static void
+gnome_two_password_dialog_finalize (GObject *object)
+{
+	GnomeTwoPasswordDialog *password_dialog;
+	
+	password_dialog = GNOME_TWO_PASSWORD_DIALOG (object);
+
+	g_object_unref (password_dialog->details->username_entry);
+	g_object_unref (password_dialog->details->domain_entry);
+	g_object_unref (password_dialog->details->password_entry);
+	g_object_unref (password_dialog->details->password_entry_secondary);
+
+	g_free (password_dialog->details->remember_label_text);
+	g_free (password_dialog->details->secondary_password_label);
+	g_free (password_dialog->details);
+
+	if (G_OBJECT_CLASS (parent_class)->finalize != NULL)
+		(* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+/* GtkDialog callbacks */
+static void
+dialog_show_callback (GtkWidget *widget, gpointer callback_data)
+{
+	GnomeTwoPasswordDialog *password_dialog;
+
+	password_dialog = GNOME_TWO_PASSWORD_DIALOG (callback_data);
+
+	if (GTK_WIDGET_VISIBLE (password_dialog->details->username_entry) &&
+	    !password_dialog->details->readonly_username) {
+		gtk_widget_grab_focus (password_dialog->details->username_entry);
+	} else if (GTK_WIDGET_VISIBLE (password_dialog->details->domain_entry) &&
+		   !password_dialog->details->readonly_domain) {
+		gtk_widget_grab_focus (password_dialog->details->domain_entry);
+	} else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry)) {
+		gtk_widget_grab_focus (password_dialog->details->password_entry);
+	} else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry_secondary)) {
+		gtk_widget_grab_focus (password_dialog->details->password_entry_secondary);
+	}
+}
+
+static void
+dialog_close_callback (GtkWidget *widget, gpointer callback_data)
+{
+	gtk_widget_hide (widget);
+}
+
+static void
+userpass_radio_button_clicked (GtkWidget *widget, gpointer callback_data)
+{
+	GnomeTwoPasswordDialog *password_dialog;
+
+	password_dialog = GNOME_TWO_PASSWORD_DIALOG (callback_data);
+
+	if (widget == password_dialog->details->connect_with_no_userpass_button) {
+		gtk_widget_set_sensitive (
+			password_dialog->details->table, FALSE);
+	}
+	else { /* the other button */
+		gtk_widget_set_sensitive (
+                        password_dialog->details->table, TRUE);
+	}	
+}
+
+static void
+add_row (GtkWidget *table, int row, const char *label_text, GtkWidget *entry)
+{
+	GtkWidget *label;
+
+	label = gtk_label_new_with_mnemonic (label_text);
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+	gtk_table_attach_defaults (GTK_TABLE (table), label,
+				   0, 1, row, row + 1);
+	gtk_table_attach_defaults (GTK_TABLE (table), entry,
+				   1, 2, row, row + 1);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+}
+
+static void
+remove_child (GtkWidget *child, GtkWidget *table)
+{
+	gtk_container_remove (GTK_CONTAINER (table), child);
+}
+
+static void
+add_table_rows (GnomeTwoPasswordDialog *password_dialog)
+{
+	int row;
+	GtkWidget *table;
+	int offset;
+
+	if (password_dialog->details->anon_support_on) {
+		offset = 12;
+	}
+	else {
+		offset = 0;
+	}
+
+	gtk_alignment_set_padding (GTK_ALIGNMENT (password_dialog->details->table_alignment),
+				   0, 0, offset, 0);
+
+	table = password_dialog->details->table;
+	/* This will not kill the entries, since they are ref:ed */
+	gtk_container_foreach (GTK_CONTAINER (table),
+			       (GtkCallback)remove_child, table);
+	
+	row = 0;
+	if (password_dialog->details->show_username)
+		add_row (table, row++, _("_Username:"), password_dialog->details->username_entry);
+	if (password_dialog->details->show_domain)
+		add_row (table, row++, _("_Domain:"), password_dialog->details->domain_entry);
+	if (password_dialog->details->show_password)
+		add_row (table, row++, _("_Password:"), password_dialog->details->password_entry);
+	if (password_dialog->details->show_password_secondary)
+		add_row (table, row++, password_dialog->details->secondary_password_label, 
+			 password_dialog->details->password_entry_secondary);
+
+	gtk_widget_show_all (table);
+}
+
+static void
+username_entry_activate (GtkWidget *widget, GtkWidget *dialog)
+{
+	GnomeTwoPasswordDialog *password_dialog;
+
+	password_dialog = GNOME_TWO_PASSWORD_DIALOG (dialog);
+	
+	if (GTK_WIDGET_VISIBLE (password_dialog->details->domain_entry) &&
+	    GTK_WIDGET_SENSITIVE (password_dialog->details->domain_entry))
+		gtk_widget_grab_focus (password_dialog->details->domain_entry);
+	else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry) &&
+		 GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry))
+		gtk_widget_grab_focus (password_dialog->details->password_entry);
+	else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry_secondary) &&
+		 GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry_secondary))
+		gtk_widget_grab_focus (password_dialog->details->password_entry_secondary);
+}
+
+static void
+domain_entry_activate (GtkWidget *widget, GtkWidget *dialog)
+{
+	GnomeTwoPasswordDialog *password_dialog;
+
+	password_dialog = GNOME_TWO_PASSWORD_DIALOG (dialog);
+	
+	if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry) &&
+	    GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry))
+		gtk_widget_grab_focus (password_dialog->details->password_entry);
+	else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry_secondary) &&
+		 GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry_secondary))
+		gtk_widget_grab_focus (password_dialog->details->password_entry_secondary);
+}
+
+
+/* Public GnomeTwoPasswordDialog methods */
+GtkWidget *
+gnome_two_password_dialog_new (const char	*dialog_title,
+			   const char	*message,
+			   const char	*username,
+			   const char	*password,
+			   gboolean	 readonly_username)
+{
+	GnomeTwoPasswordDialog *password_dialog;
+	GtkDialog *dialog;
+	GtkWidget *table;
+	GtkLabel *message_label;
+	GtkWidget *hbox;
+	GtkWidget *vbox;
+	GtkWidget *main_vbox;
+	GtkWidget *dialog_icon;
+	GSList *group;
+
+	password_dialog = GNOME_TWO_PASSWORD_DIALOG (gtk_widget_new (gnome_two_password_dialog_get_type (), NULL));
+	dialog = GTK_DIALOG (password_dialog);
+
+	gtk_window_set_title (GTK_WINDOW (password_dialog), dialog_title);
+	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+	gtk_dialog_add_buttons (dialog,
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK, GTK_RESPONSE_OK,
+				NULL);
+	gtk_dialog_set_default_response (GTK_DIALOG (password_dialog), GTK_RESPONSE_OK);
+
+	/* Setup the dialog */
+	gtk_dialog_set_has_separator (dialog, FALSE);
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+        gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
+        gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
+        gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
+
+ 	gtk_window_set_position (GTK_WINDOW (password_dialog), GTK_WIN_POS_CENTER);
+	gtk_window_set_modal (GTK_WINDOW (password_dialog), TRUE);
+
+	g_signal_connect (password_dialog, "show",
+			  G_CALLBACK (dialog_show_callback), password_dialog);
+	g_signal_connect (password_dialog, "close",
+			  G_CALLBACK (dialog_close_callback), password_dialog);
+
+	/* the radio buttons for anonymous login */
+	password_dialog->details->connect_with_no_userpass_button =
+                gtk_radio_button_new_with_mnemonic (NULL, _("Connect _anonymously"));
+	group = gtk_radio_button_get_group (
+			GTK_RADIO_BUTTON (password_dialog->details->connect_with_no_userpass_button));
+        password_dialog->details->connect_with_userpass_button =
+                gtk_radio_button_new_with_mnemonic (
+			group, _("Connect as _user:"));
+
+	if (username != NULL && *username != 0) {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->connect_with_userpass_button), TRUE);
+	} else {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->connect_with_no_userpass_button), TRUE);
+	}
+	
+	password_dialog->details->radio_vbox = gtk_vbox_new (FALSE, 6);
+	gtk_box_pack_start (GTK_BOX (password_dialog->details->radio_vbox),
+		password_dialog->details->connect_with_no_userpass_button,
+		FALSE, FALSE, 0);	
+	gtk_box_pack_start (GTK_BOX (password_dialog->details->radio_vbox),
+                password_dialog->details->connect_with_userpass_button,
+                FALSE, FALSE, 0);
+	g_signal_connect (password_dialog->details->connect_with_no_userpass_button, "clicked",
+                          G_CALLBACK (userpass_radio_button_clicked), password_dialog);
+	g_signal_connect (password_dialog->details->connect_with_userpass_button, "clicked",
+                          G_CALLBACK (userpass_radio_button_clicked), password_dialog);	
+
+	/* The table that holds the captions */
+	password_dialog->details->table_alignment = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
+
+	password_dialog->details->table = table = gtk_table_new (3, 2, FALSE);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+	gtk_container_add (GTK_CONTAINER (password_dialog->details->table_alignment), table);
+
+	password_dialog->details->username_entry = gtk_entry_new ();
+	password_dialog->details->domain_entry = gtk_entry_new ();
+	password_dialog->details->password_entry = gtk_entry_new ();
+	password_dialog->details->password_entry_secondary = gtk_entry_new ();
+
+	/* We want to hold on to these during the table rearrangement */
+#if GLIB_CHECK_VERSION (2, 10, 0)
+	g_object_ref_sink (password_dialog->details->username_entry);
+	g_object_ref_sink (password_dialog->details->domain_entry);
+        g_object_ref_sink (password_dialog->details->password_entry);
+        g_object_ref_sink (password_dialog->details->password_entry_secondary);
+#else
+	g_object_ref (password_dialog->details->username_entry);
+	gtk_object_sink (GTK_OBJECT (password_dialog->details->username_entry));
+	g_object_ref (password_dialog->details->domain_entry);
+	gtk_object_sink (GTK_OBJECT (password_dialog->details->domain_entry));
+        g_object_ref (password_dialog->details->password_entry);
+	gtk_object_sink (GTK_OBJECT (password_dialog->details->password_entry));
+        g_object_ref (password_dialog->details->password_entry_secondary);
+	gtk_object_sink (GTK_OBJECT (password_dialog->details->password_entry_secondary));
+#endif
+	
+	gtk_entry_set_visibility (GTK_ENTRY (password_dialog->details->password_entry), FALSE);
+	gtk_entry_set_visibility (GTK_ENTRY (password_dialog->details->password_entry_secondary), FALSE);
+
+	g_signal_connect (password_dialog->details->username_entry,
+			  "activate",
+			  G_CALLBACK (username_entry_activate),
+			  password_dialog);
+	g_signal_connect (password_dialog->details->domain_entry,
+			  "activate",
+			  G_CALLBACK (domain_entry_activate),
+			  password_dialog);
+	g_signal_connect_swapped (password_dialog->details->password_entry,
+				  "activate",
+				  G_CALLBACK (gtk_window_activate_default),
+				  password_dialog);
+	g_signal_connect_swapped (password_dialog->details->password_entry_secondary,
+				  "activate",
+				  G_CALLBACK (gtk_window_activate_default),
+				  password_dialog);
+	add_table_rows (password_dialog);
+
+	/* Adds some eye-candy to the dialog */
+	hbox = gtk_hbox_new (FALSE, 12);
+ 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+	dialog_icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
+	gtk_misc_set_alignment (GTK_MISC (dialog_icon), 0.5, 0.0);
+	gtk_box_pack_start (GTK_BOX (hbox), dialog_icon, FALSE, FALSE, 0);
+
+	/* Fills the vbox */
+	main_vbox = gtk_vbox_new (FALSE, 18);
+
+	if (message) {
+		message_label = GTK_LABEL (gtk_label_new (message));
+		gtk_label_set_justify (message_label, GTK_JUSTIFY_LEFT);
+		gtk_label_set_line_wrap (message_label, TRUE);
+
+		gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (message_label),
+				    FALSE, FALSE, 0);
+	}
+
+	vbox = gtk_vbox_new (FALSE, 6);
+	gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->radio_vbox,
+                            FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->table_alignment,
+			    FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (hbox), main_vbox, FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (password_dialog)->vbox),
+			    hbox,
+			    TRUE,	/* expand */
+			    TRUE,	/* fill */
+			    0);       	/* padding */
+	
+	gtk_widget_show_all (GTK_DIALOG (password_dialog)->vbox);
+
+	password_dialog->details->remember_session_button =
+		gtk_check_button_new_with_mnemonic (_("_Remember passwords for this session"));
+	password_dialog->details->remember_forever_button =
+		gtk_check_button_new_with_mnemonic (_("_Save passwords in keyring"));
+
+	gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->remember_session_button, 
+			    FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->remember_forever_button, 
+			    FALSE, FALSE, 0);
+
+	gnome_two_password_dialog_set_username (password_dialog, username);
+	gnome_two_password_dialog_set_password (password_dialog, password);
+	gnome_two_password_dialog_set_readonly_domain (password_dialog, readonly_username);
+	
+	return GTK_WIDGET (password_dialog);
+}
+
+gboolean
+gnome_two_password_dialog_run_and_block (GnomeTwoPasswordDialog *password_dialog)
+{
+	gint button_clicked;
+
+	g_return_val_if_fail (password_dialog != NULL, FALSE);
+	g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), FALSE);
+
+	button_clicked = gtk_dialog_run (GTK_DIALOG (password_dialog));
+	gtk_widget_hide (GTK_WIDGET (password_dialog));
+
+	return button_clicked == GTK_RESPONSE_OK;
+}
+
+void
+gnome_two_password_dialog_set_username (GnomeTwoPasswordDialog	*password_dialog,
+				       const char		*username)
+{
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+	g_return_if_fail (password_dialog->details->username_entry != NULL);
+
+	gtk_entry_set_text (GTK_ENTRY (password_dialog->details->username_entry),
+			    username?username:"");
+}
+
+void
+gnome_two_password_dialog_set_password (GnomeTwoPasswordDialog	*password_dialog,
+				       const char		*password)
+{
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	gtk_entry_set_text (GTK_ENTRY (password_dialog->details->password_entry),
+			    password ? password : "");
+}
+
+void
+gnome_two_password_dialog_set_password_secondary (GnomeTwoPasswordDialog	*password_dialog,
+						  const char		        *password_secondary)
+{
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	gtk_entry_set_text (GTK_ENTRY (password_dialog->details->password_entry_secondary),
+			    password_secondary ? password_secondary : "");
+}
+
+void
+gnome_two_password_dialog_set_domain (GnomeTwoPasswordDialog	*password_dialog,
+				  const char		*domain)
+{
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+	g_return_if_fail (password_dialog->details->domain_entry != NULL);
+
+	gtk_entry_set_text (GTK_ENTRY (password_dialog->details->domain_entry),
+			    domain ? domain : "");
+}
+
+
+void
+gnome_two_password_dialog_set_show_username (GnomeTwoPasswordDialog *password_dialog,
+					 gboolean             show)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	show = !!show;
+	if (password_dialog->details->show_username != show) {
+		password_dialog->details->show_username = show;
+		add_table_rows (password_dialog);
+	}
+}
+
+void
+gnome_two_password_dialog_set_show_domain (GnomeTwoPasswordDialog *password_dialog,
+				       gboolean             show)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	show = !!show;
+	if (password_dialog->details->show_domain != show) {
+		password_dialog->details->show_domain = show;
+		add_table_rows (password_dialog);
+	}
+}
+
+void
+gnome_two_password_dialog_set_show_password (GnomeTwoPasswordDialog *password_dialog,
+					 gboolean             show)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	show = !!show;
+	if (password_dialog->details->show_password != show) {
+		password_dialog->details->show_password = show;
+		add_table_rows (password_dialog);
+	}
+}
+
+void
+gnome_two_password_dialog_set_show_password_secondary (GnomeTwoPasswordDialog *password_dialog,
+						       gboolean             show)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	show = !!show;
+	if (password_dialog->details->show_password_secondary != show) {
+		password_dialog->details->show_password_secondary = show;
+		add_table_rows (password_dialog);
+	}
+}
+
+void
+gnome_two_password_dialog_set_readonly_username (GnomeTwoPasswordDialog	*password_dialog,
+						gboolean		readonly)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	password_dialog->details->readonly_username = readonly;
+
+	gtk_widget_set_sensitive (password_dialog->details->username_entry,
+				  !readonly);
+}
+
+void
+gnome_two_password_dialog_set_readonly_domain (GnomeTwoPasswordDialog	*password_dialog,
+					   gboolean		readonly)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	password_dialog->details->readonly_domain = readonly;
+
+	gtk_widget_set_sensitive (password_dialog->details->domain_entry,
+				  !readonly);
+}
+
+char *
+gnome_two_password_dialog_get_username (GnomeTwoPasswordDialog *password_dialog)
+{
+	g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
+
+	return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->username_entry)));
+}
+
+char *
+gnome_two_password_dialog_get_domain (GnomeTwoPasswordDialog *password_dialog)
+{
+	g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
+	
+	return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->domain_entry)));
+}
+
+char *
+gnome_two_password_dialog_get_password (GnomeTwoPasswordDialog *password_dialog)
+{
+	g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
+
+	return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->password_entry)));
+}
+
+char *
+gnome_two_password_dialog_get_password_secondary (GnomeTwoPasswordDialog *password_dialog)
+{
+	g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
+
+	return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->password_entry_secondary)));
+}
+
+void
+gnome_two_password_dialog_set_show_userpass_buttons (GnomeTwoPasswordDialog         *password_dialog,
+						     gboolean                     show_userpass_buttons)
+{
+        if (show_userpass_buttons) {
+                password_dialog->details->anon_support_on = TRUE;
+                gtk_widget_show (password_dialog->details->radio_vbox);
+                if (gtk_toggle_button_get_active (
+                        GTK_TOGGLE_BUTTON (password_dialog->details->connect_with_no_userpass_button))) {
+                        gtk_widget_set_sensitive (password_dialog->details->table, FALSE);
+                }
+                else {
+                        gtk_widget_set_sensitive (password_dialog->details->table, TRUE);
+                }
+        } else {
+                password_dialog->details->anon_support_on = FALSE;
+                gtk_widget_hide (password_dialog->details->radio_vbox);
+                gtk_widget_set_sensitive (password_dialog->details->table, TRUE);
+        }
+                                                                                                                             
+        add_table_rows (password_dialog);
+}
+
+gboolean
+gnome_two_password_dialog_anon_selected (GnomeTwoPasswordDialog *password_dialog)
+{
+	return password_dialog->details->anon_support_on &&
+		gtk_toggle_button_get_active (
+        		GTK_TOGGLE_BUTTON (
+				password_dialog->details->connect_with_no_userpass_button));
+}
+
+void
+gnome_two_password_dialog_set_show_remember (GnomeTwoPasswordDialog         *password_dialog,
+					 gboolean                     show_remember)
+{
+	if (show_remember) {
+		gtk_widget_show (password_dialog->details->remember_session_button);
+		gtk_widget_show (password_dialog->details->remember_forever_button);
+	} else {
+		gtk_widget_hide (password_dialog->details->remember_session_button);
+		gtk_widget_hide (password_dialog->details->remember_forever_button);
+	}
+}
+
+void
+gnome_two_password_dialog_set_remember      (GnomeTwoPasswordDialog         *password_dialog,
+					 GnomeTwoPasswordDialogRemember  remember)
+{
+	gboolean session, forever;
+
+	session = FALSE;
+	forever = FALSE;
+	if (remember == GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION) {
+		session = TRUE;
+	} else if (remember == GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER){
+		forever = TRUE;
+	}
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_session_button),
+				      session);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_forever_button),
+				      forever);
+}
+
+GnomeTwoPasswordDialogRemember
+gnome_two_password_dialog_get_remember (GnomeTwoPasswordDialog         *password_dialog)
+{
+	gboolean session, forever;
+
+	session = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_session_button));
+	forever = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_forever_button));
+	if (forever) {
+		return GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER;
+	} else if (session) {
+		return GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION;
+	}
+	return GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING;
+}
+
+void gnome_two_password_dialog_set_password_secondary_label (GnomeTwoPasswordDialog  *password_dialog,
+							     const char              *password_secondary_label)
+{
+	g_return_if_fail (password_dialog != NULL);
+	g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
+
+	g_free (password_dialog->details->secondary_password_label);
+	password_dialog->details->secondary_password_label = g_strdup (password_secondary_label);
+
+	if (password_dialog->details->show_password_secondary) {
+		add_table_rows (password_dialog);
+	}
+}

Added: trunk/auth-dialog/gnome-two-password-dialog.h
==============================================================================
--- (empty file)
+++ trunk/auth-dialog/gnome-two-password-dialog.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,116 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* gnome-two-password-dialog.h - A use password prompting dialog widget
+                                 asking for two passwords. Based of
+                                 gnome-password-dialog.[ch] from libgnomeui
+
+   Copyright (C) 1999, 2000 Eazel, Inc.
+   Copyright (C) 2005, Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Authors: Ramiro Estrugo <ramiro eazel com>
+*/
+
+#ifndef GNOME_TWO_PASSWORD_DIALOG_H
+#define GNOME_TWO_PASSWORD_DIALOG_H
+
+#include <gtk/gtkdialog.h>
+
+G_BEGIN_DECLS
+
+#define GNOME_TYPE_TWO_PASSWORD_DIALOG            (gnome_two_password_dialog_get_type ())
+#define GNOME_TWO_PASSWORD_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_TWO_PASSWORD_DIALOG, GnomeTwoPasswordDialog))
+#define GNOME_TWO_PASSWORD_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_TWO_PASSWORD_DIALOG, GnomeTwoPasswordDialogClass))
+#define GNOME_IS_TWO_PASSWORD_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_TWO_PASSWORD_DIALOG))
+#define GNOME_IS_TWO_PASSWORD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_TWO_PASSWORD_DIALOG))
+
+typedef struct GnomeTwoPasswordDialog        GnomeTwoPasswordDialog;
+typedef struct GnomeTwoPasswordDialogClass   GnomeTwoPasswordDialogClass;
+typedef struct GnomeTwoPasswordDialogDetails GnomeTwoPasswordDialogDetails;
+
+struct GnomeTwoPasswordDialog
+{
+	GtkDialog gtk_dialog;
+
+	GnomeTwoPasswordDialogDetails *details;
+};
+
+struct GnomeTwoPasswordDialogClass
+{
+	GtkDialogClass parent_class;
+};
+
+typedef enum {
+	GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING,
+	GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION,
+	GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER
+} GnomeTwoPasswordDialogRemember;
+
+
+GType    gnome_two_password_dialog_get_type (void);
+GtkWidget* gnome_two_password_dialog_new      (const char *dialog_title,
+					   const char *message,
+					   const char *username,
+					   const char *password,
+					   gboolean    readonly_username);
+
+gboolean   gnome_two_password_dialog_run_and_block           (GnomeTwoPasswordDialog *password_dialog);
+
+/* Attribute mutators */
+void gnome_two_password_dialog_set_show_username           (GnomeTwoPasswordDialog *password_dialog,
+							    gboolean                show);
+void gnome_two_password_dialog_set_show_domain             (GnomeTwoPasswordDialog *password_dialog,
+							    gboolean                show);
+void gnome_two_password_dialog_set_show_password           (GnomeTwoPasswordDialog *password_dialog,
+							    gboolean                show);
+void gnome_two_password_dialog_set_show_password_secondary (GnomeTwoPasswordDialog *password_dialog,
+							    gboolean                show);
+void gnome_two_password_dialog_set_username                (GnomeTwoPasswordDialog  *password_dialog,
+							    const char              *username);
+void gnome_two_password_dialog_set_domain                  (GnomeTwoPasswordDialog  *password_dialog,
+							    const char              *domain);
+void gnome_two_password_dialog_set_password                (GnomeTwoPasswordDialog  *password_dialog,
+							    const char              *password);
+void gnome_two_password_dialog_set_password_secondary      (GnomeTwoPasswordDialog  *password_dialog,
+							    const char              *password_secondary);
+void gnome_two_password_dialog_set_readonly_username       (GnomeTwoPasswordDialog  *password_dialog,
+							    gboolean                 readonly);
+void gnome_two_password_dialog_set_readonly_domain         (GnomeTwoPasswordDialog  *password_dialog,
+							    gboolean                 readonly);
+
+void gnome_two_password_dialog_set_password_secondary_label (GnomeTwoPasswordDialog  *password_dialog,
+							     const char              *password_secondary_description);
+
+void                           gnome_two_password_dialog_set_show_remember         (GnomeTwoPasswordDialog         *password_dialog,
+										    gboolean                        show_remember);
+void                           gnome_two_password_dialog_set_remember              (GnomeTwoPasswordDialog         *password_dialog,
+										    GnomeTwoPasswordDialogRemember  remember);
+GnomeTwoPasswordDialogRemember gnome_two_password_dialog_get_remember              (GnomeTwoPasswordDialog         *password_dialog);
+void                           gnome_two_password_dialog_set_show_userpass_buttons (GnomeTwoPasswordDialog         *password_dialog,
+										    gboolean                        show_userpass_buttons);
+
+/* Attribute accessors */
+char *     gnome_two_password_dialog_get_username            (GnomeTwoPasswordDialog *password_dialog);
+char *     gnome_two_password_dialog_get_domain              (GnomeTwoPasswordDialog *password_dialog);
+char *     gnome_two_password_dialog_get_password            (GnomeTwoPasswordDialog *password_dialog);
+char *     gnome_two_password_dialog_get_password_secondary  (GnomeTwoPasswordDialog *password_dialog);
+
+gboolean   gnome_two_password_dialog_anon_selected           (GnomeTwoPasswordDialog *password_dialog);
+
+G_END_DECLS
+
+#endif /* GNOME_TWO_PASSWORD_DIALOG_H */

Added: trunk/auth-dialog/main.c
==============================================================================
--- (empty file)
+++ trunk/auth-dialog/main.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,187 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libgnomeui/libgnomeui.h>
+
+#include <nm-setting-vpn.h>
+
+#include "src/nm-pptp-service.h"
+#include "common-gnome/keyring-helpers.h"
+#include "gnome-two-password-dialog.h"
+
+#define KEYRING_UUID_TAG "connection-uuid"
+#define KEYRING_SN_TAG "setting-name"
+#define KEYRING_SK_TAG "setting-key"
+
+static gboolean
+get_secrets (const char *vpn_uuid,
+             const char *vpn_name,
+             const char *vpn_service,
+             gboolean retry,
+             char **password)
+{
+	GnomeTwoPasswordDialog *dialog;
+	gboolean is_session = TRUE;
+	char *prompt;
+
+	g_return_val_if_fail (vpn_uuid != NULL, FALSE);
+	g_return_val_if_fail (vpn_name != NULL, FALSE);
+	g_return_val_if_fail (password != NULL, FALSE);
+	g_return_val_if_fail (*password == NULL, FALSE);
+
+	*password = keyring_helpers_lookup_secret (vpn_uuid, NM_PPTP_KEY_PASSWORD, &is_session);
+	if (!retry && *password)
+		return TRUE;
+
+	prompt = g_strdup_printf (_("You need to authenticate to access the Virtual Private Network '%s'."), vpn_name);
+	dialog = GNOME_TWO_PASSWORD_DIALOG (gnome_two_password_dialog_new (_("Authenticate VPN"), prompt, NULL, NULL, FALSE));
+	g_free (prompt);
+
+	gnome_two_password_dialog_set_show_username (dialog, FALSE);
+	gnome_two_password_dialog_set_show_userpass_buttons (dialog, FALSE);
+	gnome_two_password_dialog_set_show_domain (dialog, FALSE);
+	gnome_two_password_dialog_set_show_remember (dialog, TRUE);
+	gnome_two_password_dialog_set_show_password_secondary (dialog, FALSE);
+
+	/* If nothing was found in the keyring, default to not remembering any secrets */
+	if (*password) {
+		/* Otherwise set default remember based on which keyring the secrets were found in */
+		if (is_session)
+			gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION);
+		else
+			gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER);
+	} else
+		gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING);
+
+	/* if retrying, pre-fill dialog with the password */
+	if (*password) {
+		gnome_two_password_dialog_set_password (dialog, *password);
+		g_free (*password);
+		*password = NULL;
+	}
+
+	gtk_widget_show (GTK_WIDGET (dialog));
+
+	if (gnome_two_password_dialog_run_and_block (dialog)) {
+		const char *keyring = NULL;
+		gboolean save = FALSE;
+
+		*password = gnome_two_password_dialog_get_password (dialog);
+
+		switch (gnome_two_password_dialog_get_remember (dialog)) {
+		case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION:
+			keyring = "session";
+			/* Fall through */
+		case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER:
+			save = TRUE;
+			break;
+		default:
+			break;
+		}
+
+		if (save) {
+			if (*password) {
+				keyring_helpers_save_secret (vpn_uuid, vpn_name, keyring,
+					   	NM_PPTP_KEY_PASSWORD, *password);
+			}
+		}
+	}
+
+	gtk_widget_hide (GTK_WIDGET (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+
+	return TRUE;
+}
+
+int 
+main (int argc, char *argv[])
+{
+	gboolean retry = FALSE;
+	gchar *vpn_name = NULL;
+	gchar *vpn_uuid = NULL;
+	gchar *vpn_service = NULL;
+	char *password = NULL;
+	char buf[1];
+	int ret, exit_status = 1;
+	GOptionContext *context;
+	GnomeProgram *program;
+	GOptionEntry entries[] = {
+			{ "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
+			{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &vpn_uuid, "UUID of VPN connection", NULL},
+			{ "name", 'n', 0, G_OPTION_ARG_STRING, &vpn_name, "Name of VPN connection", NULL},
+			{ "service", 's', 0, G_OPTION_ARG_STRING, &vpn_service, "VPN service type", NULL},
+			{ NULL }
+		};
+
+	bindtextdomain (GETTEXT_PACKAGE, NULL);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	context = g_option_context_new ("- pptp auth dialog");
+	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+
+	program = gnome_program_init ("nm-pptp-auth-dialog", VERSION,
+				      LIBGNOMEUI_MODULE,
+				      argc, argv,
+				      GNOME_PARAM_GOPTION_CONTEXT, context,
+				      GNOME_PARAM_NONE);
+
+	if (vpn_uuid == NULL || vpn_name == NULL || vpn_service == NULL) {
+		fprintf (stderr, "Have to supply UUID, name, and service\n");
+		goto out;
+	}
+
+	if (strcmp (vpn_service, NM_DBUS_SERVICE_PPTP) != 0) {
+		fprintf (stderr, "This dialog only works with the '%s' service\n", NM_DBUS_SERVICE_PPTP);
+		goto out;		
+	}
+
+	if (!get_secrets (vpn_uuid, vpn_name, vpn_service, retry, &password))
+		goto out;
+
+	/* dump the passwords to stdout */
+	printf ("%s\n%s\n", NM_PPTP_KEY_PASSWORD, password);
+	printf ("\n\n");
+
+	if (password) {
+		memset (password, 0, strlen (password));
+		gnome_keyring_memory_free (password);
+	}
+	exit_status = 0;
+
+	/* for good measure, flush stdout since Kansas is going Bye-Bye */
+	fflush (stdout);
+
+	/* wait for data on stdin  */
+	ret = fread (buf, sizeof (char), sizeof (buf), stdin);
+
+out:
+	g_object_unref (program);
+	return exit_status;
+}

Added: trunk/autogen.sh
==============================================================================
--- (empty file)
+++ trunk/autogen.sh	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+REQUIRED_AUTOMAKE_VERSION=1.9
+PKG_NAME=NetworkManager-pptp
+
+(test -f $srcdir/configure.in \
+  && test -f $srcdir/auth-dialog/main.c) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level $PKG_NAME directory"
+    exit 1
+}
+
+
+which gnome-autogen.sh || {
+    echo "You need to install gnome-common from the GNOME CVS"
+    exit 1
+}
+USE_GNOME2_MACROS=1 . gnome-autogen.sh
+
+

Added: trunk/common-gnome/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/common-gnome/Makefile.am	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,17 @@
+noinst_LTLIBRARIES=libnm-pptp-common-gnome.la
+
+libnm_pptp_common_gnome_la_CPPFLAGS = \
+	$(NM_UTILS_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(GNOMEKEYRING_CFLAGS) \
+	-DG_DISABLE_DEPRECATED
+
+libnm_pptp_common_gnome_la_SOURCES= \
+	keyring-helpers.c \
+	keyring-helpers.h
+
+libnm_pptp_common_gnome_la_LIBADD = \
+	$(NM_UTILS_LIBS) \
+	$(GLIB_LIBS) \
+	$(GNOMEKEYRING_LIBS)
+

Added: trunk/common-gnome/keyring-helpers.c
==============================================================================
--- (empty file)
+++ trunk/common-gnome/keyring-helpers.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,158 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2004 - 2008 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gnome-keyring-memory.h>
+
+#include <nm-setting-vpn.h>
+
+#include "keyring-helpers.h"
+#include "../src/nm-pptp-service.h"
+
+#define KEYRING_UUID_TAG "connection-uuid"
+#define KEYRING_SN_TAG "setting-name"
+#define KEYRING_SK_TAG "setting-key"
+
+char *
+keyring_helpers_lookup_secret (const char *vpn_uuid,
+                   const char *secret_name,
+                   gboolean *is_session)
+{
+	GList *found_list = NULL;
+	GnomeKeyringResult ret;
+	GnomeKeyringFound *found;
+	char *secret;
+
+	ret = gnome_keyring_find_itemsv_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+	                                      &found_list,
+	                                      KEYRING_UUID_TAG,
+	                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+	                                      vpn_uuid,
+	                                      KEYRING_SN_TAG,
+	                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+	                                      NM_SETTING_VPN_SETTING_NAME,
+	                                      KEYRING_SK_TAG,
+	                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+	                                      secret_name,
+	                                      NULL);
+	if ((ret != GNOME_KEYRING_RESULT_OK) || (g_list_length (found_list) == 0))
+		return NULL;
+
+	found = (GnomeKeyringFound *) found_list->data;
+
+	if (is_session) {
+		if (strcmp (found->keyring, "session") == 0)
+			*is_session = TRUE;
+		else
+			*is_session = FALSE;
+	}
+
+	secret = found->secret ? gnome_keyring_memory_strdup (found->secret) : NULL;
+	gnome_keyring_found_list_free (found_list);
+
+	return secret;
+}
+
+GnomeKeyringResult
+keyring_helpers_save_secret (const char *vpn_uuid,
+                             const char *vpn_name,
+                             const char *keyring,
+                             const char *secret_name,
+                             const char *secret)
+{
+	char *display_name;
+	GnomeKeyringResult ret;
+	GnomeKeyringAttributeList *attrs = NULL;
+	guint32 id = 0;
+
+	display_name = g_strdup_printf ("VPN %s secret for %s/%s/" NM_SETTING_VPN_SETTING_NAME,
+	                                secret_name,
+	                                vpn_name,
+	                                NM_DBUS_SERVICE_PPTP);
+
+	attrs = gnome_keyring_attribute_list_new ();
+	gnome_keyring_attribute_list_append_string (attrs,
+	                                            KEYRING_UUID_TAG,
+	                                            vpn_uuid);
+	gnome_keyring_attribute_list_append_string (attrs,
+	                                            KEYRING_SN_TAG,
+	                                            NM_SETTING_VPN_SETTING_NAME);
+	gnome_keyring_attribute_list_append_string (attrs,
+	                                            KEYRING_SK_TAG,
+	                                            secret_name);
+
+	ret = gnome_keyring_item_create_sync (keyring,
+	                                      GNOME_KEYRING_ITEM_GENERIC_SECRET,
+	                                      display_name,
+	                                      attrs,
+	                                      secret,
+	                                      TRUE,
+	                                      &id);
+	gnome_keyring_attribute_list_free (attrs);
+	g_free (display_name);
+	return ret;
+}
+
+static void
+ignore_callback (GnomeKeyringResult result, gpointer data)
+{
+}
+
+gboolean
+keyring_helpers_delete_secret (const char *vpn_uuid,
+                               const char *secret_name)
+{
+	GList *found = NULL, *iter;
+	GnomeKeyringResult ret;
+
+	g_return_val_if_fail (vpn_uuid != NULL, FALSE);
+	g_return_val_if_fail (secret_name != NULL, FALSE);
+
+	ret = gnome_keyring_find_itemsv_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+	                                      &found,
+	                                      KEYRING_UUID_TAG,
+	                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+	                                      vpn_uuid,
+	                                      KEYRING_SN_TAG,
+	                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+	                                      NM_SETTING_VPN_SETTING_NAME,
+	                                      KEYRING_SK_TAG,
+	                                      GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+	                                      secret_name,
+	                                      NULL);
+	if (ret != GNOME_KEYRING_RESULT_OK && ret != GNOME_KEYRING_RESULT_NO_MATCH)
+		return FALSE;
+	if (g_list_length (found) == 0)
+		return TRUE;
+
+	/* delete them all */
+	for (iter = found; iter; iter = g_list_next (iter)) {
+		GnomeKeyringFound *item = (GnomeKeyringFound *) iter->data;
+
+		gnome_keyring_item_delete (item->keyring, item->item_id,
+		                           ignore_callback, NULL, NULL);
+	}
+
+	gnome_keyring_found_list_free (found);
+	return TRUE;
+}
+

Added: trunk/common-gnome/keyring-helpers.h
==============================================================================
--- (empty file)
+++ trunk/common-gnome/keyring-helpers.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2004 - 2008 Red Hat, Inc.
+ */
+
+#ifndef KEYRING_HELPERS_H
+#define KEYRING_HELPERS_H
+
+#include <glib.h>
+#include <gnome-keyring.h>
+#include <gnome-keyring-memory.h>
+
+char *keyring_helpers_lookup_secret (
+		const char *vpn_uuid,
+		const char *secret_name,
+		gboolean *is_session);
+
+GnomeKeyringResult keyring_helpers_save_secret (
+		const char *vpn_uuid,
+		const char *vpn_name,
+		const char *keyring,
+		const char *secret_name,
+		const char *secret);
+
+gboolean keyring_helpers_delete_secret (
+		const char *vpn_uuid,
+		const char *secret_name);
+
+#endif  /* KEYRING_HELPERS_H */
+

Added: trunk/configure.in
==============================================================================
--- (empty file)
+++ trunk/configure.in	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,142 @@
+AC_PREREQ(2.59)
+
+AC_INIT(NetworkManager-pptp, 0.7.0, dcbw redhat com, NetworkManager-pptp)
+AC_CONFIG_AUX_DIR(.)
+AM_INIT_AUTOMAKE([1.9 foreign no-dist-gzip dist-bzip2 subdir-objects])
+AM_MAINTAINER_MODE
+
+AC_CONFIG_HEADER(config.h)
+
+dnl
+dnl Require programs
+dnl
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+dnl
+dnl Required headers
+dnl
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h paths.h sys/ioctl.h sys/time.h syslog.h unistd.h)
+
+AC_CHECK_HEADERS(pppd/pppd.h,,
+  AC_MSG_ERROR(couldn't find pppd.h. pppd development headers are required.))
+
+AC_ARG_WITH([pppd-plugin-dir], AS_HELP_STRING([--with-pppd-plugin-dir=DIR], [path to the pppd plugins directory]))
+
+if test -n "$with_pppd_plugin_dir" ; then
+	PPPD_PLUGIN_DIR="$with_pppd_plugin_dir"
+else
+	PPPD_PLUGIN_DIR="${libdir}/pppd/2.4.4"
+fi
+AC_SUBST(PPPD_PLUGIN_DIR)
+
+dnl
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_HEADER_TIME
+
+dnl
+dnl Checks for library functions.
+dnl
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MEMCMP
+AC_CHECK_FUNCS(select socket uname)
+
+dnl
+dnl GNOME support
+dnl
+AC_ARG_WITH(gnome, AC_HELP_STRING([--without-gnome], [Build NetworkManager-pptp without GNOME support, e.g. vpn service only]))
+AM_CONDITIONAL(WITH_GNOME, test x"$with_gnome" != xno)
+
+GETTEXT_PACKAGE=NetworkManager-pptp
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
+
+IT_PROG_INTLTOOL([0.35])
+AM_GLIB_GNU_GETTEXT
+
+PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
+AC_SUBST(GTHREAD_CFLAGS)
+AC_SUBST(GTHREAD_LIBS)
+
+PKG_CHECK_MODULES(DBUS, dbus-glib-1 >= 0.74)
+AC_SUBST(DBUS_GLIB_CFLAGS)
+AC_SUBST(DBUS_GLIB_LIBS)
+
+PKG_CHECK_MODULES(NM_UTILS, NetworkManager >= 0.7.0 libnm-util libnm_glib libnm_glib_vpn)
+AC_SUBST(NM_UTILS_CFLAGS)
+AC_SUBST(NM_UTILS_LIBS)
+
+if test x"$with_gnome" != xno; then
+	PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.6)
+	AC_SUBST(GTK_CFLAGS)
+	AC_SUBST(GTK_LIBS)
+
+	PKG_CHECK_MODULES(GDK_PIXBUF, gdk-pixbuf-2.0)
+	AC_SUBST(GDK_PIXBUF_CFLAGS)
+	AC_SUBST(GDK_PIXBUF_LIBS)
+
+	PKG_CHECK_MODULES(GLADE, libglade-2.0)
+	AC_SUBST(GLADE_CFLAGS)
+	AC_SUBST(GLADE_LIBS)
+
+	PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0)
+	AC_SUBST(LIBGNOMEUI_CFLAGS)
+	AC_SUBST(LIBGNOMEUI_LIBS)
+
+	PKG_CHECK_MODULES(GCONF, gconf-2.0)
+	AC_SUBST(GCONF_CFLAGS)
+	AC_SUBST(GCONF_LIBS)
+
+	PKG_CHECK_MODULES(GNOMEKEYRING, gnome-keyring-1)
+	AC_SUBST(GNOMEKEYRING_CFLAGS)
+	AC_SUBST(GNOMEKEYRING_LIBS)
+fi
+
+AC_ARG_ENABLE(more-warnings,
+AC_HELP_STRING([--enable-more-warnings], [Maximum compiler warnings]),
+set_more_warnings="$enableval",[
+if test -d "$srcdir/{arch}" || test -d "$srcdir/CVS"; then
+	set_more_warnings=yes
+else
+	set_more_warnings=no
+fi
+])
+AC_MSG_CHECKING(for more warnings, including -Werror)
+if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
+	AC_MSG_RESULT(yes)
+	CFLAGS="-Wall -Werror -std=gnu89 $CFLAGS"
+
+	for option in -Wno-unused -Wno-strict-aliasing -Wno-sign-compare -Wdeclaration-after-statement -Wno-pointer-sign ; do
+		SAVE_CFLAGS="$CFLAGS"
+		CFLAGS="$CFLAGS $option"
+		AC_MSG_CHECKING([whether gcc understands $option])
+		AC_TRY_COMPILE([], [],
+			has_option=yes,
+			has_option=no,)
+		if test $has_option = no; then
+			CFLAGS="$SAVE_CFLAGS"
+		fi
+		AC_MSG_RESULT($has_option)
+		unset has_option
+		unset SAVE_CFLAGS
+	done
+	unset option
+else
+	AC_MSG_RESULT(no)
+fi
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+common-gnome/Makefile
+auth-dialog/Makefile
+properties/Makefile
+po/Makefile.in
+])
+

Added: trunk/doc/example-pptp-system-wide-connection.sh
==============================================================================
--- (empty file)
+++ trunk/doc/example-pptp-system-wide-connection.sh	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# This is an example of how to install a system-wide connection that
+# cannot be edited by unprivileged users using nm-vpn-properties. This
+# script needs to be run as root and you may need to restart any
+# gconfd daemons after the script has run (logging in and out will
+# suffice)
+
+NAME="ppp-system-wide"
+ESCAPED_NAME="ppp-system-wide"
+REMOTE="1.2.3.4"
+# must be either yes or no
+USEMPPE="yes"
+
+IPSEC_ROUTES="[172.16.0.0/16,192.168.4.0/24]"
+
+GCONF_PATH="/system/networking/vpn_connections/$ESCAPED_NAME"
+
+GCONFTOOL2_OPTS="--direct --config-source xml:readwrite:/etc/gconf/gconf.xml.mandatory"
+
+gconftool-2 $GCONFTOOL2_OPTS --type string --set $GCONF_PATH/name "$NAME"
+gconftool-2 $GCONFTOOL2_OPTS --type string --set $GCONF_PATH/service_name "org.freedesktop.NetworkManager.ppp_starter"
+gconftool-2 $GCONFTOOL2_OPTS --type list --list-type=string --set $GCONF_PATH/vpn_data ["pptp-remote","$REMOTE","encrypt-mppe",$USEMPPE]
+gconftool-2 $GCONFTOOL2_OPTS --type list --list-type=string --set $GCONF_PATH/routes $IPSEC_ROUTES
+

Added: trunk/gnome-mime-application-x-pptp-settings.png
==============================================================================
Binary file. No diff available.

Added: trunk/nm-pptp-service.conf
==============================================================================
--- (empty file)
+++ trunk/nm-pptp-service.conf	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,24 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd";>
+<busconfig>
+	<policy user="root">
+		<allow own="org.freedesktop.NetworkManager.pptp"/>
+		<allow send_destination="org.freedesktop.NetworkManager.pptp"/>
+		<allow send_interface="org.freedesktop.NetworkManager.pptp"/>
+
+		<allow own="org.freedesktop.NetworkManager.pptp-ppp"/>
+		<allow send_destination="org.freedesktop.NetworkManager.pptp-ppp"/>
+		<allow send_interface="org.freedesktop.NetworkManager.pptp-ppp"/>
+	</policy>
+	<policy context="default">
+		<deny own="org.freedesktop.NetworkManager.pptp"/>
+		<deny send_destination="org.freedesktop.NetworkManager.pptp"/>
+		<deny send_interface="org.freedesktop.NetworkManager.pptp"/>
+
+		<deny own="org.freedesktop.NetworkManager.pptp-ppp"/>
+		<deny send_destination="org.freedesktop.NetworkManager.pptp-ppp"/>
+		<deny send_interface="org.freedesktop.NetworkManager.pptp-ppp"/>
+	</policy>
+</busconfig>
+

Added: trunk/nm-pptp-service.name.in
==============================================================================
--- (empty file)
+++ trunk/nm-pptp-service.name.in	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,8 @@
+[VPN Connection]
+name=pptp
+service=org.freedesktop.NetworkManager.pptp
+program= LIBEXECDIR@/nm-pptp-service
+
+[GNOME]
+auth-dialog=nm-pptp-auth-dialog
+properties=libnm-pptp-properties

Added: trunk/nm-pptp.desktop.in
==============================================================================
--- (empty file)
+++ trunk/nm-pptp.desktop.in	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Encoding=UTF-8
+_Name=PPTP VPN Connection Manager
+_GenericName=PPTP VPN Connection Manager
+_Comment=Add, Remove, and Edit PPTP VPN Connections
+Exec=nm-vpn-properties --import-service org.freedesktop.NetworkManager.pptp --import-file %f
+Icon=gnome-mime-application-x-ppp-settings
+Terminal=false
+Type=Application
+DocPath=
+Categories=GNOME;Application;Network;
+MimeType=application/x-ppp-settings
+NoDisplay=true

Added: trunk/po/.cvsignore
==============================================================================
--- (empty file)
+++ trunk/po/.cvsignore	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,8 @@
+Makefile.in.in
+Makefile
+Makefile.in
+POTFILES
+*.gmo
+*.pot
+.intltool-merge-cache
+stamp-it

Added: trunk/po/LINGUAS
==============================================================================
--- (empty file)
+++ trunk/po/LINGUAS	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,40 @@
+# please keep this list sorted alphabetically
+#
+ar
+be latin
+bg
+ca
+cs
+da
+de
+dz
+el
+en_GB
+es
+et
+eu
+fi
+fr
+gl
+he
+hu
+it
+ja
+ka
+ko
+lt
+mk
+nb
+nl
+pa
+pl
+pt
+pt_BR
+ru
+sv
+th
+uk
+vi
+zh_CN
+zh_HK
+zh_TW

Added: trunk/po/POTFILES.in
==============================================================================
--- (empty file)
+++ trunk/po/POTFILES.in	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,9 @@
+# List of source files containing translatable strings.
+# Please keep this file sorted alphabetically.
+auth-dialog/gnome-two-password-dialog.c
+auth-dialog/main.c
+nm-pptp.desktop.in
+properties/advanced-dialog.c
+properties/nm-pptp-dialog.glade
+properties/nm-pptp.c
+src/nm-pptp-service.c

Added: trunk/properties/.cvsignore
==============================================================================
--- (empty file)
+++ trunk/properties/.cvsignore	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,4 @@
+Makefile.in
+Makefile
+.libs
+.deps

Added: trunk/properties/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/properties/Makefile.am	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,44 @@
+plugindir = $(libdir)/NetworkManager
+plugin_LTLIBRARIES = libnm-pptp-properties.la
+
+libnm_pptp_properties_la_SOURCES = \
+	nm-pptp.c \
+	nm-pptp.h \
+	advanced-dialog.c \
+	advanced-dialog.h \
+	import-export.c \
+	import-export.h
+
+gladedir = $(datadir)/gnome-vpn-properties/pptp
+glade_DATA = nm-pptp-dialog.glade
+
+libnm_pptp_properties_la_CFLAGS =                    \
+        $(GLADE_CFLAGS)                                 \
+        $(GTK_CFLAGS)                                   \
+        $(GCONF_CFLAGS)                                 \
+        $(LIBGNOMEUI_CFLAGS)                            \
+        $(GNOMEKEYRING_CFLAGS)                          \
+        $(NM_UTILS_CFLAGS)                              \
+        -DICONDIR=\""$(datadir)/pixmaps"\"              \
+        -DGLADEDIR=\""$(gladedir)"\"                    \
+        -DG_DISABLE_DEPRECATED                          \
+        -DGDK_DISABLE_DEPRECATED                        \
+        -DGNOME_DISABLE_DEPRECATED                      \
+        -DGNOMELOCALEDIR=\"$(datadir)/locale\"          \
+        -DVERSION=\"$(VERSION)\"
+
+libnm_pptp_properties_la_LIBADD =    \
+        $(GLADE_LIBS)                   \
+        $(GTK_LIBS)                     \
+        $(GCONF_LIBS)                   \
+        $(LIBGNOMEUI_LIBS)              \
+        $(top_builddir)/common-gnome/libnm-pptp-common-gnome.la	\
+        $(NM_UTILS_LIBS)
+
+libnm_pptp_properties_la_LDFLAGS =   \
+        -avoid-version
+
+CLEANFILES = *.bak *.gladep *~
+
+EXTRA_DIST =                            \
+        $(glade_DATA)

Added: trunk/properties/advanced-dialog.c
==============================================================================
--- (empty file)
+++ trunk/properties/advanced-dialog.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,453 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glade/glade.h>
+
+#include <nm-connection.h>
+#include <nm-setting-vpn.h>
+
+#include "advanced-dialog.h"
+#include "nm-pptp.h"
+#include "../src/nm-pptp-service.h"
+
+#define COL_NAME  0
+#define COL_VALUE 1
+#define COL_TAG 2
+
+#define TAG_PAP      0
+#define TAG_CHAP     1
+#define TAG_MSCHAP   2
+#define TAG_MSCHAPV2 3
+#define TAG_EAP      4
+
+static const char *advanced_keys[] = {
+	NM_PPTP_KEY_REFUSE_EAP,
+	NM_PPTP_KEY_REFUSE_PAP,
+	NM_PPTP_KEY_REFUSE_CHAP,
+	NM_PPTP_KEY_REFUSE_MSCHAP,
+	NM_PPTP_KEY_REFUSE_MSCHAPV2,
+	NM_PPTP_KEY_REQUIRE_MPPE,
+	NM_PPTP_KEY_REQUIRE_MPPE_40,
+	NM_PPTP_KEY_REQUIRE_MPPE_128,
+	NM_PPTP_KEY_MPPE_STATEFUL,
+	NM_PPTP_KEY_NOBSDCOMP,
+	NM_PPTP_KEY_NODEFLATE,
+	NM_PPTP_KEY_NO_VJ_COMP,
+	NM_PPTP_KEY_LCP_ECHO_FAILURE,
+	NM_PPTP_KEY_LCP_ECHO_INTERVAL,
+	NULL
+};
+
+static void
+copy_values (const char *key, const char *value, gpointer user_data)
+{
+	GHashTable *hash = (GHashTable *) user_data;
+	const char **i;
+
+	for (i = &advanced_keys[0]; *i; i++) {
+		if (strcmp (key, *i))
+			continue;
+		g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
+	}
+}
+
+GHashTable *
+advanced_dialog_new_hash_from_connection (NMConnection *connection,
+                                          GError **error)
+{
+	GHashTable *hash;
+	NMSettingVPN *s_vpn;
+
+	hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+	s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+	nm_setting_vpn_foreach_data_item (s_vpn, copy_values, hash);
+	return hash;
+}
+
+static void
+mppe_toggled_cb (GtkWidget *check, gpointer user_data)
+{
+	GladeXML *xml = (GladeXML *) user_data;
+	GtkWidget *widget;
+	gboolean use_mppe;
+
+	use_mppe = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check));
+
+	widget = glade_xml_get_widget (xml, "ppp_mppe_security_label");
+	gtk_widget_set_sensitive (widget, use_mppe);
+
+	widget = glade_xml_get_widget (xml, "ppp_mppe_security_combo");
+	if (!use_mppe)
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); /* default */
+	gtk_widget_set_sensitive (widget, use_mppe);
+
+	widget = glade_xml_get_widget (xml, "ppp_allow_stateful_mppe");
+	if (!use_mppe)
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+	gtk_widget_set_sensitive (widget, use_mppe);
+}
+
+#define SEC_INDEX_DEFAULT   0
+#define SEC_INDEX_MPPE_128  1
+#define SEC_INDEX_MPPE_40   2
+
+static void
+setup_security_combo (GladeXML *xml, GHashTable *hash)
+{
+	GtkWidget *widget;
+	GtkListStore *store;
+	GtkTreeIter iter;
+	int active = -1;
+	const char *value;
+
+	g_return_if_fail (xml != NULL);
+	g_return_if_fail (hash != NULL);
+
+	widget = glade_xml_get_widget (xml, "ppp_mppe_security_combo");
+
+	store = gtk_list_store_new (1, G_TYPE_STRING);
+
+	/* Default (allow use of all encryption types that both server and client support) */
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, 0, _("All Available (Default)"), -1);
+
+	/* MPPE-128 */
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, 0, _("128-bit (most secure)"), -1);
+	if (active < 0) {
+		value = g_hash_table_lookup (hash, NM_PPTP_KEY_REQUIRE_MPPE_128);
+		if (value && !strcmp (value, "yes"))
+			active = SEC_INDEX_MPPE_128;
+	}
+
+	/* MPPE-40 */
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, 0, _("40-bit (less secure)"), -1);
+	if (active < 0) {
+		value = g_hash_table_lookup (hash, NM_PPTP_KEY_REQUIRE_MPPE_40);
+		if (value && !strcmp (value, "yes"))
+			active = SEC_INDEX_MPPE_40;
+	}
+
+	gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
+	g_object_unref (store);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active < 0 ? SEC_INDEX_DEFAULT : active);
+}
+
+static void
+check_toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer user_data)
+{
+	GladeXML *xml = GLADE_XML (user_data);
+	GtkWidget *widget;
+	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean toggle_item;
+
+	widget = glade_xml_get_widget (xml, "ppp_auth_methods");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter, COL_VALUE, &toggle_item, -1);
+
+	toggle_item ^= 1;
+
+	/* set new value */
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_VALUE, toggle_item, -1);
+
+	gtk_tree_path_free (path);
+}
+
+static void
+auth_methods_setup (GladeXML *xml, GHashTable *hash)
+{
+	GtkWidget *widget;
+	GtkListStore *store;
+	GtkTreeIter iter;
+	const char *value;
+	gboolean allowed;
+	gboolean use_mppe = FALSE;
+	GtkCellRendererToggle *check_renderer;
+	GtkCellRenderer *text_renderer;
+	GtkTreeViewColumn *column;
+	gint offset;
+
+	store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT);
+
+	/* Check for MPPE */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REQUIRE_MPPE);
+	if (value && !strcmp (value, "yes"))
+		use_mppe = TRUE;
+	
+	/* Or MPPE-128 */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REQUIRE_MPPE_128);
+	if (value && !strcmp (value, "yes"))
+		use_mppe = TRUE;
+
+	/* Or MPPE-40 */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REQUIRE_MPPE_40);
+	if (value && !strcmp (value, "yes"))
+		use_mppe = TRUE;
+
+	/* PAP */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REFUSE_PAP);
+	allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, COL_NAME, _("PAP"), COL_VALUE, allowed, COL_TAG, TAG_PAP, -1);
+
+	/* CHAP */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REFUSE_CHAP);
+	allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, COL_NAME, _("CHAP"), COL_VALUE, allowed, COL_TAG, TAG_CHAP, -1);
+
+	/* MSCHAP */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REFUSE_MSCHAP);
+	allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, COL_NAME, _("MSCHAP"), COL_VALUE, allowed, COL_TAG, TAG_MSCHAP, -1);
+
+	/* MSCHAPv2 */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REFUSE_MSCHAPV2);
+	allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, COL_NAME, _("MSCHAPv2"), COL_VALUE, allowed, COL_TAG, TAG_MSCHAPV2, -1);
+
+	/* EAP */
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REFUSE_EAP);
+	allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, COL_NAME, _("EAP"), COL_VALUE, allowed, COL_TAG, TAG_EAP, -1);
+
+	/* Set up the tree view */
+	widget = glade_xml_get_widget (xml, "ppp_auth_methods");
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget), GTK_TREE_MODEL (store));
+
+	check_renderer = GTK_CELL_RENDERER_TOGGLE (gtk_cell_renderer_toggle_new ());
+	g_signal_connect (check_renderer, "toggled", G_CALLBACK (check_toggled_cb), xml);
+
+	offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
+	                                                      -1, "", GTK_CELL_RENDERER (check_renderer),
+	                                                      "active", COL_VALUE,
+	                                                      NULL);
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
+	gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED);
+	gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 30);
+	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+
+	text_renderer = gtk_cell_renderer_text_new ();
+	offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
+	                                                      -1, "", text_renderer,
+	                                                      "text", COL_NAME,
+	                                                      NULL);
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
+}
+
+GtkWidget *
+advanced_dialog_new (GHashTable *hash)
+{
+	GladeXML *xml;
+	GtkWidget *dialog = NULL;
+	char *glade_file = NULL;
+	GtkWidget *widget;
+	const char *value;
+
+	g_return_val_if_fail (hash != NULL, NULL);
+
+	glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-pptp-dialog.glade");
+	xml = glade_xml_new (glade_file, "pptp-advanced-dialog", GETTEXT_PACKAGE);
+	if (xml == NULL)
+		goto out;
+
+	dialog = glade_xml_get_widget (xml, "pptp-advanced-dialog");
+	if (!dialog) {
+		g_object_unref (G_OBJECT (xml));
+		goto out;
+	}
+	gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+	g_object_set_data_full (G_OBJECT (dialog), "glade-xml",
+	                        xml, (GDestroyNotify) g_object_unref);
+
+	setup_security_combo (xml, hash);
+
+	widget = glade_xml_get_widget (xml, "ppp_use_mppe");
+	g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (mppe_toggled_cb), xml);
+
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_REQUIRE_MPPE);
+	if (value && !strcmp (value, "yes"))
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+	mppe_toggled_cb (widget, xml);
+
+	widget = glade_xml_get_widget (xml, "ppp_allow_stateful_mppe");
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_MPPE_STATEFUL);
+	if (value && !strcmp (value, "yes"))
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+	widget = glade_xml_get_widget (xml, "ppp_allow_bsdcomp");
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_NOBSDCOMP);
+	if (value && !strcmp (value, "yes"))
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+	widget = glade_xml_get_widget (xml, "ppp_allow_deflate");
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_NODEFLATE);
+	if (value && !strcmp (value, "yes"))
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+	widget = glade_xml_get_widget (xml, "ppp_usevj");
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_NO_VJ_COMP);
+	if (value && !strcmp (value, "yes"))
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+	widget = glade_xml_get_widget (xml, "ppp_send_echo_packets");
+	value = g_hash_table_lookup (hash, NM_PPTP_KEY_LCP_ECHO_INTERVAL);
+	if (value && strlen (value)) {
+		long int tmp_int;
+
+		errno = 0;
+		tmp_int = strtol (value, NULL, 10);
+		if (errno == 0 && tmp_int > 0)
+			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+	}
+
+	auth_methods_setup (xml, hash);
+
+out:
+	g_free (glade_file);
+	return dialog;
+}
+
+GHashTable *
+advanced_dialog_new_hash_from_dialog (GtkWidget *dialog, GError **error)
+{
+	GHashTable *hash;
+	GtkWidget *widget;
+	GladeXML *xml;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean valid;
+
+	g_return_val_if_fail (dialog != NULL, NULL);
+	if (error)
+		g_return_val_if_fail (*error == NULL, NULL);
+
+	xml = g_object_get_data (G_OBJECT (dialog), "glade-xml");
+	g_return_val_if_fail (xml != NULL, NULL);
+
+	hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+	widget = glade_xml_get_widget (xml, "ppp_use_mppe");
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+
+		widget = glade_xml_get_widget (xml, "ppp_mppe_security_combo");
+		switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget))) {
+		case SEC_INDEX_MPPE_128:
+			g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REQUIRE_MPPE_128), g_strdup ("yes"));
+			break;
+		case SEC_INDEX_MPPE_40:
+			g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REQUIRE_MPPE_40), g_strdup ("yes"));
+			break;
+		default:
+			g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REQUIRE_MPPE), g_strdup ("yes"));
+			break;
+		}
+
+		widget = glade_xml_get_widget (xml, "ppp_allow_stateful_mppe");
+		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+			g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_MPPE_STATEFUL), g_strdup ("yes"));
+	}
+
+	widget = glade_xml_get_widget (xml, "ppp_allow_bsdcomp");
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+		g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_NOBSDCOMP), g_strdup ("yes"));
+
+	widget = glade_xml_get_widget (xml, "ppp_allow_deflate");
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+		g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_NODEFLATE), g_strdup ("yes"));
+
+	widget = glade_xml_get_widget (xml, "ppp_usevj");
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+		g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_NO_VJ_COMP), g_strdup ("yes"));
+
+	widget = glade_xml_get_widget (xml, "ppp_send_echo_packets");
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+		g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_LCP_ECHO_FAILURE), g_strdup_printf ("%d", 5));
+		g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_LCP_ECHO_INTERVAL), g_strdup_printf ("%d", 30));
+	}
+
+	widget = glade_xml_get_widget (xml, "ppp_auth_methods");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	while (valid) {
+		gboolean allowed;
+		guint32 tag;
+
+		gtk_tree_model_get (model, &iter, COL_VALUE, &allowed, COL_TAG, &tag, -1);
+		switch (tag) {
+		case TAG_PAP:
+			if (!allowed)
+				g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REFUSE_PAP), g_strdup ("yes"));
+			break;
+		case TAG_CHAP:
+			if (!allowed)
+				g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REFUSE_CHAP), g_strdup ("yes"));
+			break;
+		case TAG_MSCHAP:
+			if (!allowed)
+				g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REFUSE_MSCHAP), g_strdup ("yes"));
+			break;
+		case TAG_MSCHAPV2:
+			if (!allowed)
+				g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REFUSE_MSCHAPV2), g_strdup ("yes"));
+			break;
+		case TAG_EAP:
+			if (!allowed)
+				g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_REFUSE_EAP), g_strdup ("yes"));
+			break;
+		default:
+			break;
+		}
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	return hash;
+}
+

Added: trunk/properties/advanced-dialog.h
==============================================================================
--- (empty file)
+++ trunk/properties/advanced-dialog.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifndef _AUTH_HELPERS_H_
+#define _AUTH_HELPERS_H_
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkwidget.h>
+
+#include <nm-connection.h>
+
+GtkWidget *advanced_dialog_new (GHashTable *hash);
+
+GHashTable *advanced_dialog_new_hash_from_connection (NMConnection *connection, GError **error);
+
+GHashTable *advanced_dialog_new_hash_from_dialog (GtkWidget *dialog, GError **error);
+
+#endif

Added: trunk/properties/import-export.c
==============================================================================
--- (empty file)
+++ trunk/properties/import-export.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <glib/gi18n-lib.h>
+
+#include <nm-setting-vpn.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+
+#include "import-export.h"
+#include "nm-pptp.h"
+#include "../src/nm-pptp-service.h"
+
+NMConnection *
+do_import (const char *path, char **lines, GError **error)
+{
+	return NULL;
+}
+
+gboolean
+do_export (const char *path, NMConnection *connection, GError **error)
+{
+	return FALSE;
+}
+
+
+

Added: trunk/properties/import-export.h
==============================================================================
--- (empty file)
+++ trunk/properties/import-export.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifndef _IMPORT_EXPORT_H_
+#define _IMPORT_EXPORT_H_
+
+#include <glib.h>
+#include <nm-connection.h>
+
+NMConnection *do_import (const char *path, char **lines, GError **error);
+
+gboolean do_export (const char *path, NMConnection *connection, GError **error);
+
+#endif

Added: trunk/properties/nm-pptp-dialog.glade
==============================================================================
--- (empty file)
+++ trunk/properties/nm-pptp-dialog.glade	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,586 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.4 on Sun Oct 12 10:59:11 2008 -->
+<glade-interface>
+  <widget class="GtkWindow" id="pptp-widget">
+    <property name="title" translatable="yes">window1</property>
+    <child>
+      <widget class="GtkVBox" id="pptp-vbox">
+        <property name="visible">True</property>
+        <property name="border_width">12</property>
+        <property name="spacing">16</property>
+        <child>
+          <widget class="GtkVBox" id="vbox8">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label22">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="alignment8">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="table2">
+                    <property name="visible">True</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">12</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkEntry" id="gateway_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label23">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Gateway:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">gateway_entry</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="vbox11">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label25">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Optional&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="alignment9">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="table3">
+                    <property name="visible">True</property>
+                    <property name="n_rows">4</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">12</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="domain_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label27">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">NT Domain:</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="show_passwords_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Show password</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="user_password_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="visibility">False</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Password:</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="user_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label26">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">User name:</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkAlignment" id="alignment1">
+            <property name="visible">True</property>
+            <property name="xalign">1</property>
+            <property name="xscale">0</property>
+            <child>
+              <widget class="GtkButton" id="advanced_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="response_id">0</property>
+                <child>
+                  <widget class="GtkHBox" id="hbox2">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <widget class="GtkImage" id="image1">
+                        <property name="visible">True</property>
+                        <property name="stock">gtk-preferences</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Ad_vanced...</property>
+                        <property name="use_markup">True</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="pptp-advanced-dialog">
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="icon_name">stock-preferences</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox3">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="PppPage">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+            <property name="spacing">18</property>
+            <child>
+              <widget class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label28">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Authentication&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkVBox" id="vbox4">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <widget class="GtkLabel" id="auth_methods_label">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Allow the following authentication methods:</property>
+                          </widget>
+                        </child>
+                        <child>
+                          <widget class="GtkScrolledWindow" id="scrolledwindow1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                            <property name="shadow_type">GTK_SHADOW_IN</property>
+                            <child>
+                              <widget class="GtkTreeView" id="ppp_auth_methods">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="headers_visible">False</property>
+                              </widget>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox5">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label29">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Security and Compression&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkAlignment" id="alignment3">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkVBox" id="vbox6">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox7">
+                            <property name="visible">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <widget class="GtkCheckButton" id="ppp_use_mppe">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Use _Point-to-Point encryption (MPPE)</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkAlignment" id="alignment4">
+                                <property name="visible">True</property>
+                                <property name="left_padding">12</property>
+                                <child>
+                                  <widget class="GtkVBox" id="vbox1">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <widget class="GtkHBox" id="hbox1">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">12</property>
+                                        <child>
+                                          <widget class="GtkLabel" id="ppp_mppe_security_label">
+                                            <property name="visible">True</property>
+                                            <property name="xalign">0</property>
+                                            <property name="label" translatable="yes">_Security:</property>
+                                            <property name="use_underline">True</property>
+                                            <property name="mnemonic_widget">ppp_mppe_security_combo</property>
+                                          </widget>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <widget class="GtkComboBox" id="ppp_mppe_security_combo">
+                                            <property name="visible">True</property>
+                                            <property name="items" translatable="yes">Default</property>
+                                          </widget>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </widget>
+                                    </child>
+                                    <child>
+                                      <widget class="GtkCheckButton" id="ppp_allow_stateful_mppe">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="label" translatable="yes">Allow st_ateful encryption</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="response_id">0</property>
+                                        <property name="draw_indicator">True</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </widget>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="ppp_allow_bsdcomp">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">Allow _BSD data compression</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="ppp_allow_deflate">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">Allow _Deflate data compression</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="ppp_usevj">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">Use TCP _header compression</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox9">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label31">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Echo&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkAlignment" id="alignment5">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkCheckButton" id="ppp_send_echo_packets">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Send PPP _echo packets</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area3">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="ok_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/properties/nm-pptp.c
==============================================================================
--- (empty file)
+++ trunk/properties/nm-pptp.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,726 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ * nm-pptp.c : GNOME UI dialogs for configuring PPTP VPN connections
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ * Based on work by David Zeuthen, <davidz redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#define NM_VPN_API_SUBJECT_TO_CHANGE
+
+#include <nm-vpn-plugin-ui-interface.h>
+#include <nm-setting-vpn.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+
+#include "../src/nm-pptp-service.h"
+#include "../common-gnome/keyring-helpers.h"
+#include "nm-pptp.h"
+#include "import-export.h"
+#include "advanced-dialog.h"
+
+#define PPTP_PLUGIN_NAME    _("Point-to-Point Tunneling Protocol (PPTP)")
+#define PPTP_PLUGIN_DESC    _("Compatible with Microsoft and other PPTP VPN servers.")
+#define PPTP_PLUGIN_SERVICE NM_DBUS_SERVICE_PPTP
+
+
+typedef void (*ChangedCallback) (GtkWidget *widget, gpointer user_data);
+
+/************** plugin class **************/
+
+static void pptp_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class);
+
+G_DEFINE_TYPE_EXTENDED (PptpPluginUi, pptp_plugin_ui, G_TYPE_OBJECT, 0,
+						G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_INTERFACE,
+											   pptp_plugin_ui_interface_init))
+
+/************** UI widget class **************/
+
+static void pptp_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class);
+
+G_DEFINE_TYPE_EXTENDED (PptpPluginUiWidget, pptp_plugin_ui_widget, G_TYPE_OBJECT, 0,
+						G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_WIDGET_INTERFACE,
+											   pptp_plugin_ui_widget_interface_init))
+
+#define PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PPTP_TYPE_PLUGIN_UI_WIDGET, PptpPluginUiWidgetPrivate))
+
+typedef struct {
+	GladeXML *xml;
+	GtkWidget *widget;
+	GtkSizeGroup *group;
+	GtkWindowGroup *window_group;
+	gboolean window_added;
+	GHashTable *advanced;
+} PptpPluginUiWidgetPrivate;
+
+
+GQuark
+pptp_plugin_ui_error_quark (void)
+{
+	static GQuark error_quark = 0;
+
+	if (G_UNLIKELY (error_quark == 0))
+		error_quark = g_quark_from_static_string ("pptp-plugin-ui-error-quark");
+
+	return error_quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+pptp_plugin_ui_error_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			/* Unknown error. */
+			ENUM_ENTRY (PPTP_PLUGIN_UI_ERROR_UNKNOWN, "UnknownError"),
+			/* The connection was missing invalid. */
+			ENUM_ENTRY (PPTP_PLUGIN_UI_ERROR_INVALID_CONNECTION, "InvalidConnection"),
+			/* The specified property was invalid. */
+			ENUM_ENTRY (PPTP_PLUGIN_UI_ERROR_INVALID_PROPERTY, "InvalidProperty"),
+			/* The specified property was missing and is required. */
+			ENUM_ENTRY (PPTP_PLUGIN_UI_ERROR_MISSING_PROPERTY, "MissingProperty"),
+			/* The file to import could not be read. */
+			ENUM_ENTRY (PPTP_PLUGIN_UI_ERROR_FILE_NOT_READABLE, "FileNotReadable"),
+			/* The file to import could was not an PPTP client file. */
+			ENUM_ENTRY (PPTP_PLUGIN_UI_ERROR_FILE_NOT_PPTP, "FileNotPPTP"),
+			{ 0, 0, 0 }
+		};
+		etype = g_enum_register_static ("PptpPluginUiError", values);
+	}
+	return etype;
+}
+
+static gboolean
+check_validity (PptpPluginUiWidget *self, GError **error)
+{
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	GtkWidget *widget;
+	const char *str;
+
+	widget = glade_xml_get_widget (priv->xml, "gateway_entry");
+	str = gtk_entry_get_text (GTK_ENTRY (widget));
+	if (!str || !strlen (str)) {
+		g_set_error (error,
+		             PPTP_PLUGIN_UI_ERROR,
+		             PPTP_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+		             NM_PPTP_KEY_GATEWAY);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+stuff_changed_cb (GtkWidget *widget, gpointer user_data)
+{
+	g_signal_emit_by_name (PPTP_PLUGIN_UI_WIDGET (user_data), "changed");
+}
+
+static void
+advanced_dialog_close_cb (GtkWidget *dialog, gpointer user_data)
+{
+	gtk_widget_hide (dialog);
+	/* gtk_widget_destroy() will remove the window from the window group */
+	gtk_widget_destroy (dialog);
+}
+
+static void
+advanced_dialog_response_cb (GtkWidget *dialog, gint response, gpointer user_data)
+{
+	PptpPluginUiWidget *self = PPTP_PLUGIN_UI_WIDGET (user_data);
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	GError *error = NULL;
+
+	if (response != GTK_RESPONSE_OK) {
+		advanced_dialog_close_cb (dialog, self);
+		return;
+	}
+
+	if (priv->advanced)
+		g_hash_table_destroy (priv->advanced);
+	priv->advanced = advanced_dialog_new_hash_from_dialog (dialog, &error);
+	if (!priv->advanced) {
+		g_message ("%s: error reading advanced settings: %s", __func__, error->message);
+		g_error_free (error);
+	}
+	advanced_dialog_close_cb (dialog, self);
+
+	stuff_changed_cb (NULL, self);
+}
+
+static void
+advanced_button_clicked_cb (GtkWidget *button, gpointer user_data)
+{
+	PptpPluginUiWidget *self = PPTP_PLUGIN_UI_WIDGET (user_data);
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	GtkWidget *dialog, *toplevel;
+
+	toplevel = gtk_widget_get_toplevel (priv->widget);
+	g_return_if_fail (GTK_WIDGET_TOPLEVEL (toplevel));
+
+	dialog = advanced_dialog_new (priv->advanced);
+	if (!dialog) {
+		g_warning ("%s: failed to create the Advanced dialog!", __func__);
+		return;
+	}
+
+	gtk_window_group_add_window (priv->window_group, GTK_WINDOW (dialog));
+	if (!priv->window_added) {
+		gtk_window_group_add_window (priv->window_group, GTK_WINDOW (toplevel));
+		priv->window_added = TRUE;
+	}
+
+	gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
+	g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (advanced_dialog_response_cb), self);
+	g_signal_connect (G_OBJECT (dialog), "close", G_CALLBACK (advanced_dialog_close_cb), self);
+
+	gtk_widget_show_all (dialog);
+}
+
+static void
+show_toggled_cb (GtkCheckButton *button, PptpPluginUiWidget *self)
+{
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	GtkWidget *widget;
+	gboolean visible;
+
+	visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+	widget = glade_xml_get_widget (priv->xml, "user_password_entry");
+	g_assert (widget);
+	gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static GtkWidget *
+fill_password (GladeXML *xml,
+               const char *widget_name,
+               NMConnection *connection,
+               const char *password_type)
+{
+	GtkWidget *widget = NULL;
+	gchar *password = NULL;
+
+	widget = glade_xml_get_widget (xml, widget_name);
+	g_assert (widget);
+
+	if (!connection)
+		return widget;
+
+	password = NULL;
+
+	if (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM) {
+		NMSettingVPN *s_vpn;
+
+		s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+		if (s_vpn) {
+			const gchar *tmp = NULL;
+
+			tmp = nm_setting_vpn_get_secret (s_vpn, password_type);
+			if (tmp)
+				password = gnome_keyring_memory_strdup (tmp);
+		}
+	} else {
+		NMSettingConnection *s_con = NULL;
+		gboolean unused;
+		const char *uuid;
+
+		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+		uuid = nm_setting_connection_get_uuid (s_con);
+		password = keyring_helpers_lookup_secret (uuid,
+		                                          password_type,
+		                                          &unused);
+	}
+
+	if (password) {
+		gtk_entry_set_text (GTK_ENTRY (widget), password);
+		gnome_keyring_memory_free (password);
+	}
+
+	return widget;
+}
+
+static void
+fill_vpn_passwords (GladeXML *xml,
+                    GtkSizeGroup *group,
+                    NMConnection *connection,
+                    ChangedCallback changed_cb,
+                    gpointer user_data)
+{
+	GtkWidget *w = NULL;
+
+	w = fill_password (xml, "user_password_entry", connection, NM_PPTP_KEY_PASSWORD);
+	if (w) {
+		gtk_size_group_add_widget (group, w);
+		g_signal_connect (w, "changed", G_CALLBACK (changed_cb), user_data);
+	} else {
+		g_error ("No user_password_entry in glade file!");
+	}
+}
+
+static gboolean
+init_plugin_ui (PptpPluginUiWidget *self, NMConnection *connection, GError **error)
+{
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	NMSettingVPN *s_vpn;
+	GtkWidget *widget;
+	const char *value;
+
+	s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+
+	priv->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+	widget = glade_xml_get_widget (priv->xml, "gateway_entry");
+	if (!widget)
+		return FALSE;
+	gtk_size_group_add_widget (priv->group, widget);
+	if (s_vpn) {
+		value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_GATEWAY);
+		if (value && strlen (value))
+			gtk_entry_set_text (GTK_ENTRY (widget), value);
+	}
+	g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
+
+	widget = glade_xml_get_widget (priv->xml, "user_entry");
+	if (!widget)
+		return FALSE;
+	gtk_size_group_add_widget (priv->group, widget);
+	if (s_vpn) {
+		value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_USER);
+		if (value && strlen (value))
+			gtk_entry_set_text (GTK_ENTRY (widget), value);
+	}
+	g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
+
+	widget = glade_xml_get_widget (priv->xml, "domain_entry");
+	if (!widget)
+		return FALSE;
+	gtk_size_group_add_widget (priv->group, widget);
+	if (s_vpn) {
+		value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_DOMAIN);
+		if (value && strlen (value))
+			gtk_entry_set_text (GTK_ENTRY (widget), value);
+	}
+	g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
+
+	widget = glade_xml_get_widget (priv->xml, "advanced_button");
+	g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (advanced_button_clicked_cb), self);
+
+	widget = glade_xml_get_widget (priv->xml, "show_passwords_checkbutton");
+	g_return_val_if_fail (widget != NULL, FALSE);
+	g_signal_connect (G_OBJECT (widget), "toggled",
+	                  (GCallback) show_toggled_cb,
+	                  self);
+
+	fill_vpn_passwords (priv->xml, priv->group, connection, stuff_changed_cb, self);
+
+	return TRUE;
+}
+
+static GObject *
+get_widget (NMVpnPluginUiWidgetInterface *iface)
+{
+	PptpPluginUiWidget *self = PPTP_PLUGIN_UI_WIDGET (iface);
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+
+	return G_OBJECT (priv->widget);
+}
+
+static void
+hash_copy_advanced (gpointer key, gpointer data, gpointer user_data)
+{
+	NMSettingVPN *s_vpn = NM_SETTING_VPN (user_data);
+
+	nm_setting_vpn_add_data_item (s_vpn, (const char *) key, (const char *) data);
+}
+
+static gboolean
+update_connection (NMVpnPluginUiWidgetInterface *iface,
+                   NMConnection *connection,
+                   GError **error)
+{
+	PptpPluginUiWidget *self = PPTP_PLUGIN_UI_WIDGET (iface);
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	NMSettingVPN *s_vpn;
+	GtkWidget *widget;
+	const char *str;
+	gboolean valid = FALSE;
+
+	if (!check_validity (self, error))
+		return FALSE;
+
+	s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
+	g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, NM_DBUS_SERVICE_PPTP, NULL);
+
+	/* Gateway */
+	widget = glade_xml_get_widget (priv->xml, "gateway_entry");
+	str = gtk_entry_get_text (GTK_ENTRY (widget));
+	if (str && strlen (str))
+		nm_setting_vpn_add_data_item (s_vpn, NM_PPTP_KEY_GATEWAY, str);
+
+	/* Username */
+	widget = glade_xml_get_widget (priv->xml, "user_entry");
+	str = gtk_entry_get_text (GTK_ENTRY (widget));
+	if (str && strlen (str))
+		nm_setting_vpn_add_data_item (s_vpn, NM_PPTP_KEY_USER, str);
+
+	/* Domain */
+	widget = glade_xml_get_widget (priv->xml, "domain_entry");
+	str = gtk_entry_get_text (GTK_ENTRY (widget));
+	if (str && strlen (str))
+		nm_setting_vpn_add_data_item (s_vpn, NM_PPTP_KEY_DOMAIN, str);
+
+	if (priv->advanced)
+		g_hash_table_foreach (priv->advanced, hash_copy_advanced, s_vpn);
+
+	nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+	valid = TRUE;
+
+	return valid;
+}
+
+static gboolean
+save_secrets (NMVpnPluginUiWidgetInterface *iface,
+              NMConnection *connection,
+              GError **error)
+{
+	PptpPluginUiWidget *self = PPTP_PLUGIN_UI_WIDGET (iface);
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+	GnomeKeyringResult ret;
+	NMSettingConnection *s_con;
+	GtkWidget *widget;
+	const char *str, *uuid, *id;
+
+	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	if (!s_con) {
+		g_set_error (error,
+		             PPTP_PLUGIN_UI_ERROR,
+		             PPTP_PLUGIN_UI_ERROR_INVALID_CONNECTION,
+		             "missing 'connection' setting");
+		return FALSE;
+	}
+
+	id = nm_setting_connection_get_id (s_con);
+	uuid = nm_setting_connection_get_uuid (s_con);
+
+    widget = glade_xml_get_widget (priv->xml, "user_password_entry");
+    g_assert (widget);
+    str = gtk_entry_get_text (GTK_ENTRY (widget));
+    if (str && strlen (str)) {
+        ret = keyring_helpers_save_secret (uuid, id, NULL, NM_PPTP_KEY_PASSWORD, str);
+        if (ret != GNOME_KEYRING_RESULT_OK)
+            g_warning ("%s: failed to save user password to keyring.", __func__);
+    } else
+        keyring_helpers_delete_secret (uuid, NM_PPTP_KEY_PASSWORD);
+
+	return TRUE;
+}
+
+static NMVpnPluginUiWidgetInterface *
+nm_vpn_plugin_ui_widget_interface_new (NMConnection *connection, GError **error)
+{
+	NMVpnPluginUiWidgetInterface *object;
+	PptpPluginUiWidgetPrivate *priv;
+	char *glade_file;
+
+	if (error)
+		g_return_val_if_fail (*error == NULL, NULL);
+
+	object = NM_VPN_PLUGIN_UI_WIDGET_INTERFACE (g_object_new (PPTP_TYPE_PLUGIN_UI_WIDGET, NULL));
+	if (!object) {
+		g_set_error (error, PPTP_PLUGIN_UI_ERROR, 0, "could not create pptp object");
+		return NULL;
+	}
+
+	priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (object);
+
+	glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-pptp-dialog.glade");
+	priv->xml = glade_xml_new (glade_file, "pptp-vbox", GETTEXT_PACKAGE);
+	if (priv->xml == NULL) {
+		g_set_error (error, PPTP_PLUGIN_UI_ERROR, 0,
+		             "could not load required resources at %s", glade_file);
+		g_free (glade_file);
+		g_object_unref (object);
+		return NULL;
+	}
+	g_free (glade_file);
+
+	priv->widget = glade_xml_get_widget (priv->xml, "pptp-vbox");
+	if (!priv->widget) {
+		g_set_error (error, PPTP_PLUGIN_UI_ERROR, 0, "could not load UI widget");
+		g_object_unref (object);
+		return NULL;
+	}
+	g_object_ref_sink (priv->widget);
+
+	priv->window_group = gtk_window_group_new ();
+
+	if (!init_plugin_ui (PPTP_PLUGIN_UI_WIDGET (object), connection, error)) {
+		g_object_unref (object);
+		return NULL;
+	}
+
+	priv->advanced = advanced_dialog_new_hash_from_connection (connection, error);
+	if (!priv->advanced) {
+		g_object_unref (object);
+		return NULL;
+	}
+
+	return object;
+}
+
+static void
+dispose (GObject *object)
+{
+	PptpPluginUiWidget *plugin = PPTP_PLUGIN_UI_WIDGET (object);
+	PptpPluginUiWidgetPrivate *priv = PPTP_PLUGIN_UI_WIDGET_GET_PRIVATE (plugin);
+
+	if (priv->group)
+		g_object_unref (priv->group);
+
+	if (priv->window_group)
+		g_object_unref (priv->window_group);
+
+	if (priv->widget)
+		g_object_unref (priv->widget);
+
+	if (priv->xml)
+		g_object_unref (priv->xml);
+
+	if (priv->advanced)
+		g_hash_table_destroy (priv->advanced);
+
+	G_OBJECT_CLASS (pptp_plugin_ui_widget_parent_class)->dispose (object);
+}
+
+static void
+pptp_plugin_ui_widget_class_init (PptpPluginUiWidgetClass *req_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+	g_type_class_add_private (req_class, sizeof (PptpPluginUiWidgetPrivate));
+
+	object_class->dispose = dispose;
+}
+
+static void
+pptp_plugin_ui_widget_init (PptpPluginUiWidget *plugin)
+{
+}
+
+static void
+pptp_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class)
+{
+	/* interface implementation */
+	iface_class->get_widget = get_widget;
+	iface_class->update_connection = update_connection;
+	iface_class->save_secrets = save_secrets;
+}
+
+static gboolean
+delete_connection (NMVpnPluginUiInterface *iface,
+                   NMConnection *connection,
+                   GError **error)
+{
+	NMSettingConnection *s_con = NULL;
+	const char *uuid;
+
+	/* Remove any secrets in the keyring associated with this connection's UUID */
+	s_con = (NMSettingConnection *) nm_connection_get_setting (connection,
+			NM_TYPE_SETTING_CONNECTION);
+	if (!s_con) {
+		g_set_error (error,
+		             PPTP_PLUGIN_UI_ERROR,
+		             PPTP_PLUGIN_UI_ERROR_INVALID_CONNECTION,
+		             "missing 'connection' setting");
+		return FALSE;
+	}
+
+	uuid = nm_setting_connection_get_uuid (s_con);
+	keyring_helpers_delete_secret (uuid, NM_PPTP_KEY_PASSWORD);
+
+	return TRUE;
+}
+
+static NMConnection *
+import (NMVpnPluginUiInterface *iface, const char *path, GError **error)
+{
+	NMConnection *connection = NULL;
+	char *contents = NULL;
+	char **lines = NULL;
+	char *ext;
+
+	ext = strrchr (path, '.');
+	if (!ext) {
+		g_set_error (error,
+		             PPTP_PLUGIN_UI_ERROR,
+		             PPTP_PLUGIN_UI_ERROR_FILE_NOT_PPTP,
+		             "unknown PPTP file extension");
+		goto out;
+	}
+
+	if (strcmp (ext, ".conf") && strcmp (ext, ".cnf")) {
+		g_set_error (error,
+		             PPTP_PLUGIN_UI_ERROR,
+		             PPTP_PLUGIN_UI_ERROR_FILE_NOT_PPTP,
+		             "unknown PPTP file extension");
+		goto out;
+	}
+
+	if (!g_file_get_contents (path, &contents, NULL, error))
+		return NULL;
+
+	lines = g_strsplit_set (contents, "\r\n", 0);
+	if (g_strv_length (lines) <= 1) {
+		g_set_error (error,
+		             PPTP_PLUGIN_UI_ERROR,
+		             PPTP_PLUGIN_UI_ERROR_FILE_NOT_READABLE,
+		             "not a valid PPTP configuration file");
+		goto out;
+	}
+
+	connection = do_import (path, lines, error);
+
+out:
+	if (lines)
+		g_strfreev (lines);
+	g_free (contents);
+	return connection;
+}
+
+static gboolean
+export (NMVpnPluginUiInterface *iface,
+        const char *path,
+        NMConnection *connection,
+        GError **error)
+{
+	return do_export (path, connection, error);
+}
+
+static char *
+get_suggested_name (NMVpnPluginUiInterface *iface, NMConnection *connection)
+{
+	NMSettingConnection *s_con;
+	const char *id;
+
+	g_return_val_if_fail (connection != NULL, NULL);
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	g_return_val_if_fail (s_con != NULL, NULL);
+
+	id = nm_setting_connection_get_id (s_con);
+	g_return_val_if_fail (id != NULL, NULL);
+
+	return g_strdup_printf ("%s (pptp).conf", id);
+}
+
+static guint32
+get_capabilities (NMVpnPluginUiInterface *iface)
+{
+	return (NM_VPN_PLUGIN_UI_CAPABILITY_IMPORT | NM_VPN_PLUGIN_UI_CAPABILITY_EXPORT);
+}
+
+static NMVpnPluginUiWidgetInterface *
+ui_factory (NMVpnPluginUiInterface *iface, NMConnection *connection, GError **error)
+{
+	return nm_vpn_plugin_ui_widget_interface_new (connection, error);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME:
+		g_value_set_string (value, PPTP_PLUGIN_NAME);
+		break;
+	case NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC:
+		g_value_set_string (value, PPTP_PLUGIN_DESC);
+		break;
+	case NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE:
+		g_value_set_string (value, PPTP_PLUGIN_SERVICE);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+pptp_plugin_ui_class_init (PptpPluginUiClass *req_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+	object_class->get_property = get_property;
+
+	g_object_class_override_property (object_class,
+									  NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME,
+									  NM_VPN_PLUGIN_UI_INTERFACE_NAME);
+
+	g_object_class_override_property (object_class,
+									  NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC,
+									  NM_VPN_PLUGIN_UI_INTERFACE_DESC);
+
+	g_object_class_override_property (object_class,
+									  NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE,
+									  NM_VPN_PLUGIN_UI_INTERFACE_SERVICE);
+}
+
+static void
+pptp_plugin_ui_init (PptpPluginUi *plugin)
+{
+}
+
+static void
+pptp_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class)
+{
+	/* interface implementation */
+	iface_class->ui_factory = ui_factory;
+	iface_class->get_capabilities = get_capabilities;
+	iface_class->import = import;
+	iface_class->export = export;
+	iface_class->get_suggested_name = get_suggested_name;
+	iface_class->delete_connection = delete_connection;
+}
+
+
+G_MODULE_EXPORT NMVpnPluginUiInterface *
+nm_vpn_plugin_ui_factory (GError **error)
+{
+	if (error)
+		g_return_val_if_fail (*error == NULL, NULL);
+
+	return NM_VPN_PLUGIN_UI_INTERFACE (g_object_new (PPTP_TYPE_PLUGIN_UI, NULL));
+}
+

Added: trunk/properties/nm-pptp.h
==============================================================================
--- (empty file)
+++ trunk/properties/nm-pptp.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,87 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ * nm-pptp.h : GNOME UI dialogs for configuring pptp VPN connections
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifndef _NM_PPTP_H_
+#define _NM_PPTP_H_
+
+#include <glib-object.h>
+
+typedef enum
+{
+	PPTP_PLUGIN_UI_ERROR_UNKNOWN = 0,
+	PPTP_PLUGIN_UI_ERROR_INVALID_CONNECTION,
+	PPTP_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+	PPTP_PLUGIN_UI_ERROR_MISSING_PROPERTY,
+	PPTP_PLUGIN_UI_ERROR_FILE_NOT_READABLE,
+	PPTP_PLUGIN_UI_ERROR_FILE_NOT_PPTP
+} PptpPluginUiError;
+
+#define PPTP_TYPE_PLUGIN_UI_ERROR (pptp_plugin_ui_error_get_type ()) 
+GType pptp_plugin_ui_error_get_type (void);
+
+#define PPTP_PLUGIN_UI_ERROR (pptp_plugin_ui_error_quark ())
+GQuark pptp_plugin_ui_error_quark (void);
+
+
+#define PPTP_TYPE_PLUGIN_UI            (pptp_plugin_ui_get_type ())
+#define PPTP_PLUGIN_UI(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PPTP_TYPE_PLUGIN_UI, PptpPluginUi))
+#define PPTP_PLUGIN_UI_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PPTP_TYPE_PLUGIN_UI, PptpPluginUiClass))
+#define PPTP_IS_PLUGIN_UI(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PPTP_TYPE_PLUGIN_UI))
+#define PPTP_IS_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), PPTP_TYPE_PLUGIN_UI))
+#define PPTP_PLUGIN_UI_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PPTP_TYPE_PLUGIN_UI, PptpPluginUiClass))
+
+typedef struct _PptpPluginUi PptpPluginUi;
+typedef struct _PptpPluginUiClass PptpPluginUiClass;
+
+struct _PptpPluginUi {
+	GObject parent;
+};
+
+struct _PptpPluginUiClass {
+	GObjectClass parent;
+};
+
+GType pptp_plugin_ui_get_type (void);
+
+
+#define PPTP_TYPE_PLUGIN_UI_WIDGET            (pptp_plugin_ui_widget_get_type ())
+#define PPTP_PLUGIN_UI_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PPTP_TYPE_PLUGIN_UI_WIDGET, PptpPluginUiWidget))
+#define PPTP_PLUGIN_UI_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PPTP_TYPE_PLUGIN_UI_WIDGET, PptpPluginUiWidgetClass))
+#define PPTP_IS_PLUGIN_UI_WIDGET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PPTP_TYPE_PLUGIN_UI_WIDGET))
+#define PPTP_IS_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), PPTP_TYPE_PLUGIN_UI_WIDGET))
+#define PPTP_PLUGIN_UI_WIDGET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PPTP_TYPE_PLUGIN_UI_WIDGET, PptpPluginUiWidgetClass))
+
+typedef struct _PptpPluginUiWidget PptpPluginUiWidget;
+typedef struct _PptpPluginUiWidgetClass PptpPluginUiWidgetClass;
+
+struct _PptpPluginUiWidget {
+	GObject parent;
+};
+
+struct _PptpPluginUiWidgetClass {
+	GObjectClass parent;
+};
+
+GType pptp_plugin_ui_widget_get_type (void);
+
+#endif	/* _NM_PPTP_H_ */
+

Added: trunk/src/.cvsignore
==============================================================================
--- (empty file)
+++ trunk/src/.cvsignore	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,7 @@
+Makefile.in
+Makefile
+nm-ppp-starter
+nm-pppd-plugin.so
+nm-pptp-service
+.libs
+.deps

Added: trunk/src/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/Makefile.am	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,57 @@
+INCLUDES = -I${top_srcdir}
+
+AM_CPPFLAGS =							\
+	$(DBUS_GLIB_CFLAGS)						\
+	$(GTHREAD_CFLAGS)					\
+	$(NM_UTILS_CFLAGS)				\
+	-DDBUS_API_SUBJECT_TO_CHANGE				\
+	-DG_DISABLE_DEPRECATED					\
+	-DBINDIR=\"$(bindir)\"					\
+	-DPREFIX=\""$(prefix)"\"				\
+	-DSYSCONFDIR=\""$(sysconfdir)"\"			\
+	-DNM_VERSION="\"$(VERSION)\""				\
+	-DLIBDIR=\""$(libdir)"\"				\
+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
+	-DLOCALSTATEDIR=\""$(localstatedir)"\"		 	\
+	-DDATADIR=\"$(datadir)\"				\
+	-DPLUGINDIR=\"$(PPPD_PLUGIN_DIR)\" 
+
+libexec_PROGRAMS = nm-pptp-service
+
+nm_pptp_service_SOURCES = \
+				nm-pptp-service.c \
+				nm-pptp-service.h
+
+nm-pptp-pppd-service-glue.h: $(top_srcdir)/src/nm-pptp-pppd-service.xml
+	dbus-binding-tool --prefix=nm_pptp_pppd_service --mode=glib-server --output=$@ $<
+
+nm_pptp_service_LDADD = 				\
+				$(DBUS_GLIB_LIBS)		\
+				$(GTHREAD_LIBS)		\
+				$(NM_UTILS_LIBS)
+
+pppd_plugindir = $(PPPD_PLUGIN_DIR)
+pppd_plugin_LTLIBRARIES = nm-pptp-pppd-plugin.la
+
+nm_pptp_pppd_plugin_la_SOURCES = \
+	nm-pptp-pppd-plugin.c \
+	nm-ppp-status.h
+
+nm_pptp_pppd_plugin_la_CPPFLAGS = \
+	$(DBUS_GLIB_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(NM_UTILS_CFLAGS)
+
+nm_pptp_pppd_plugin_la_LDFLAGS = -module -avoid-version
+
+nm_pptp_pppd_plugin_la_LIBADD = \
+	$(DBUS_GLIB_LIBS) \
+	$(GLIB_LIBS) \
+	$(NM_UTILS_LIBS)
+
+BUILT_SOURCES = nm-pptp-pppd-service-glue.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = nm-pptp-pppd-service.xml
+

Added: trunk/src/nm-ppp-status.h
==============================================================================
--- (empty file)
+++ trunk/src/nm-ppp-status.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,22 @@
+#ifndef NM_PPP_STATUS_H
+#define NM_PPP_STATUS_H
+
+typedef enum {
+	NM_PPP_STATUS_UNKNOWN,
+
+	NM_PPP_STATUS_DEAD,
+	NM_PPP_STATUS_INITIALIZE,
+	NM_PPP_STATUS_SERIALCONN,
+	NM_PPP_STATUS_DORMANT,
+	NM_PPP_STATUS_ESTABLISH,
+	NM_PPP_STATUS_AUTHENTICATE,
+	NM_PPP_STATUS_CALLBACK,
+	NM_PPP_STATUS_NETWORK,
+	NM_PPP_STATUS_RUNNING,
+	NM_PPP_STATUS_TERMINATE,
+	NM_PPP_STATUS_DISCONNECT,
+	NM_PPP_STATUS_HOLDOFF,
+	NM_PPP_STATUS_MASTER
+} NMPPPStatus;
+
+#endif /* NM_PPP_STATUS_H */

Added: trunk/src/nm-pptp-pppd-plugin.c
==============================================================================
--- (empty file)
+++ trunk/src/nm-pptp-pppd-plugin.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,324 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-pptp-service - pptp (and other pppd) integration with NetworkManager
+ *
+ * (C) 2007 - 2008 Novell, Inc.
+ * (C) 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 
+ */
+
+#include <string.h>
+#include <pppd/pppd.h>
+#include <pppd/fsm.h>
+#include <pppd/ipcp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <glib/gtypes.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#include "nm-pptp-service.h"
+#include "nm-ppp-status.h"
+
+#include <nm-utils.h>
+
+int plugin_init (void);
+
+char pppd_version[] = VERSION;
+
+static DBusGProxy *proxy = NULL;
+
+static void
+nm_phasechange (void *data, int arg)
+{
+	NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN;
+	char *ppp_phase;
+
+	g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+
+	switch (arg) {
+	case PHASE_DEAD:
+		ppp_status = NM_PPP_STATUS_DEAD;
+		ppp_phase = "dead";
+		break;
+	case PHASE_INITIALIZE:
+		ppp_status = NM_PPP_STATUS_INITIALIZE;
+		ppp_phase = "initialize";
+		break;
+	case PHASE_SERIALCONN:
+		ppp_status = NM_PPP_STATUS_SERIALCONN;
+		ppp_phase = "serial connection";
+		break;
+	case PHASE_DORMANT:
+		ppp_status = NM_PPP_STATUS_DORMANT;
+		ppp_phase = "dormant";
+		break;
+	case PHASE_ESTABLISH:
+		ppp_status = NM_PPP_STATUS_ESTABLISH;
+		ppp_phase = "establish";
+		break;
+	case PHASE_AUTHENTICATE:
+		ppp_status = NM_PPP_STATUS_AUTHENTICATE;
+		ppp_phase = "authenticate";
+		break;
+	case PHASE_CALLBACK:
+		ppp_status = NM_PPP_STATUS_CALLBACK;
+		ppp_phase = "callback";
+		break;
+	case PHASE_NETWORK:
+		ppp_status = NM_PPP_STATUS_NETWORK;
+		ppp_phase = "network";
+		break;
+	case PHASE_RUNNING:
+		ppp_status = NM_PPP_STATUS_RUNNING;
+		ppp_phase = "running";
+		break;
+	case PHASE_TERMINATE:
+		ppp_status = NM_PPP_STATUS_TERMINATE;
+		ppp_phase = "terminate";
+		break;
+	case PHASE_DISCONNECT:
+		ppp_status = NM_PPP_STATUS_DISCONNECT;
+		ppp_phase = "disconnect";
+		break;
+	case PHASE_HOLDOFF:
+		ppp_status = NM_PPP_STATUS_HOLDOFF;
+		ppp_phase = "holdoff";
+		break;
+	case PHASE_MASTER:
+		ppp_status = NM_PPP_STATUS_MASTER;
+		ppp_phase = "master";
+		break;
+
+	default:
+		ppp_phase = "unknown";
+		break;
+	}
+
+	if (ppp_status != NM_PPP_STATUS_UNKNOWN) {
+		dbus_g_proxy_call_no_reply (proxy, "SetState",
+							   G_TYPE_UINT, ppp_status,
+							   G_TYPE_INVALID,
+							   G_TYPE_INVALID);
+	}
+}
+
+static GValue *
+str_to_gvalue (const char *str)
+{
+	GValue *val;
+
+	val = g_slice_new0 (GValue);
+	g_value_init (val, G_TYPE_STRING);
+	g_value_set_string (val, str);
+
+	return val;
+}
+
+static GValue *
+uint_to_gvalue (guint32 i)
+{
+	GValue *val;
+
+	val = g_slice_new0 (GValue);
+	g_value_init (val, G_TYPE_UINT);
+	g_value_set_uint (val, i);
+
+	return val;
+}
+
+static void
+value_destroy (gpointer data)
+{
+	GValue *val = (GValue *) data;
+
+	g_value_unset (val);
+	g_slice_free (GValue, val);
+}
+
+static void
+nm_ip_up (void *data, int arg)
+{
+	guint32 pppd_made_up_address = htonl (0x0a404040 + ifunit);
+	ipcp_options opts = ipcp_gotoptions[0];
+	ipcp_options peer_opts = ipcp_hisoptions[0];
+	GHashTable *hash;
+	GArray *array;
+	GValue *val;
+
+	g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+
+	if (!opts.ouraddr) {
+		g_warning ("Didn't receive an internal IP from pppd");
+		return;
+	}
+
+	hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+							NULL, value_destroy);
+
+	g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, 
+					 str_to_gvalue (ifname));
+
+	/* Prefer the peer options remote address first, _unless_ pppd made the
+	 * address up, at which point prefer the local options remote address,
+	 * and if that's not right, use the made-up address as a last resort.
+	 */
+	if (peer_opts.hisaddr && (peer_opts.hisaddr != pppd_made_up_address)) {
+		g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP,
+		                     uint_to_gvalue (peer_opts.hisaddr));
+	} else if (opts.hisaddr) {
+		g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP,
+		                     uint_to_gvalue (opts.hisaddr));
+	} else if (peer_opts.hisaddr == pppd_made_up_address) {
+		/* As a last resort, use the made-up address */
+		g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP,
+		                     uint_to_gvalue (peer_opts.hisaddr));
+	}
+
+	g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, 
+					 uint_to_gvalue (opts.ouraddr));
+
+	g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, uint_to_gvalue (32));
+
+	if (opts.dnsaddr[0] || opts.dnsaddr[1]) {
+		array = g_array_new (FALSE, FALSE, sizeof (guint32));
+
+		if (opts.dnsaddr[0])
+			g_array_append_val (array, opts.dnsaddr[0]);
+		if (opts.dnsaddr[1])
+			g_array_append_val (array, opts.dnsaddr[1]);
+
+		val = g_slice_new0 (GValue);
+		g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
+		g_value_set_boxed (val, array);
+
+		g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
+	}
+
+	dbus_g_proxy_call_no_reply (proxy, "SetIp4Config",
+						   DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID,
+						   G_TYPE_INVALID);
+
+	g_hash_table_destroy (hash);
+}
+
+static int
+get_chap_check()
+{
+	return 1;
+}
+
+static int
+get_pap_check()
+{
+	return 1;
+}
+
+static int
+get_credentials (char *username, char *password)
+{
+	char *my_username;
+	char *my_password;
+	size_t len;
+	GError *err = NULL;
+
+	if (username && !password) {
+		/* pppd is checking pap support; return 1 for supported */
+		return 1;
+	}
+
+	g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), -1);
+
+	my_username = my_password = NULL;
+	dbus_g_proxy_call (proxy, "NeedSecrets", &err,
+				    G_TYPE_INVALID,
+				    G_TYPE_STRING, &my_username,
+				    G_TYPE_STRING, &my_password,
+				    G_TYPE_INVALID);
+
+	if (err) {
+		g_warning ("Could not get secrets: %s", err->message);
+		g_error_free (err);
+		return -1;
+	}
+
+	if (my_username) {
+		len = strlen (my_username) + 1;
+		len = len < MAXNAMELEN ? len : MAXNAMELEN;
+
+		strncpy (username, my_username, len);
+		username[len - 1] = '\0';
+
+		g_free (my_username);
+	}
+
+	if (my_password) {
+		len = strlen (my_password) + 1;
+		len = len < MAXSECRETLEN ? len : MAXSECRETLEN;
+
+		strncpy (password, my_password, len);
+		password[len - 1] = '\0';
+
+		g_free (my_password);
+	}
+
+	return 1;
+}
+
+static void
+nm_exit_notify (void *data, int arg)
+{
+	g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+
+	g_object_unref (proxy);
+	proxy = NULL;
+}
+
+int
+plugin_init (void)
+{
+	DBusGConnection *bus;
+	GError *err = NULL;
+
+	g_type_init ();
+
+	bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
+	if (!bus) {
+		g_warning ("Couldn't connect to system bus: %s", err->message);
+		g_error_free (err);
+		return -1;
+	}
+
+	proxy = dbus_g_proxy_new_for_name (bus,
+								NM_DBUS_SERVICE_PPTP_PPP,
+								NM_DBUS_PATH_PPTP_PPP,
+								NM_DBUS_INTERFACE_PPTP_PPP);
+
+	dbus_g_connection_unref (bus);
+
+	chap_passwd_hook = get_credentials;
+	chap_check_hook = get_chap_check;
+	pap_passwd_hook = get_credentials;
+	pap_check_hook = get_pap_check;
+
+	add_notifier (&phasechange, nm_phasechange, NULL);
+	add_notifier (&ip_up_notifier, nm_ip_up, NULL);
+	add_notifier (&exitnotify, nm_exit_notify, proxy);
+
+	return 0;
+}

Added: trunk/src/nm-pptp-pppd-service.xml
==============================================================================
--- (empty file)
+++ trunk/src/nm-pptp-pppd-service.xml	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/">
+  <interface name="org.freedesktop.NetworkManager.pptp.ppp">
+    <method name="NeedSecrets">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_pptp_service_need_secrets"/>
+      <arg name="username" type="s" direction="out"/>
+      <arg name="password" type="s" direction="out"/>
+    </method>
+
+    <method name="SetIp4Config">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_pptp_service_set_ip4_config"/>
+      <arg name="config" type="a{sv}" direction="in"/>
+    </method>
+
+    <method name="SetState">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_pptp_service_set_state"/>
+      <arg name="state" type="u" direction="in"/>
+    </method>
+  </interface>
+</node>

Added: trunk/src/nm-pptp-service.c
==============================================================================
--- (empty file)
+++ trunk/src/nm-pptp-service.c	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,1219 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-pptp-service - PPTP VPN integration with NetworkManager
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <ctype.h>
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+#include <linux/ppp_defs.h>
+#ifndef aligned_u64
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+#endif
+#include <linux/if_ppp.h>
+
+#include <nm-setting-vpn.h>
+#include <nm-utils.h>
+
+#include "nm-pptp-service.h"
+#include "nm-ppp-status.h"
+
+/********************************************************/
+/* ppp plugin <-> pptp-service object                   */
+/********************************************************/
+
+/* Have to have a separate objec to handle ppp plugin requests since
+ * dbus-glib doesn't allow multiple interfaces registed on one GObject.
+ */
+
+#define NM_TYPE_PPTP_PPP_SERVICE            (nm_pptp_ppp_service_get_type ())
+#define NM_PPTP_PPP_SERVICE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PPTP_PPP_SERVICE, NMPptpPppService))
+#define NM_PPTP_PPP_SERVICE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PPTP_PPP_SERVICE, NMPptpPppServiceClass))
+#define NM_IS_PPTP_PPP_SERVICE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PPTP_PPP_SERVICE))
+#define NM_IS_PPTP_PPP_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_PPTP_PPP_SERVICE))
+#define NM_PPTP_PPP_SERVICE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PPTP_PPP_SERVICE, NMPptpPppServiceClass))
+
+typedef struct {
+	GObject parent;
+} NMPptpPppService;
+
+typedef struct {
+	GObjectClass parent;
+
+	/* Signals */
+	void (*plugin_alive) (NMPptpPppService *self);
+	void (*ppp_state) (NMPptpPppService *self, guint32 state);
+	void (*ip4_config) (NMPptpPppService *self, GHashTable *config_hash);
+} NMPptpPppServiceClass;
+
+GType nm_pptp_ppp_service_get_type (void);
+
+G_DEFINE_TYPE (NMPptpPppService, nm_pptp_ppp_service, G_TYPE_OBJECT)
+
+static gboolean impl_pptp_service_need_secrets (NMPptpPppService *self,
+                                                char **out_username,
+                                                char **out_password,
+                                                GError **err);
+
+static gboolean impl_pptp_service_set_state (NMPptpPppService *self,
+                                             guint32 state,
+                                             GError **err);
+
+static gboolean impl_pptp_service_set_ip4_config (NMPptpPppService *self,
+                                                  GHashTable *config,
+                                                  GError **err);
+
+#include "nm-pptp-pppd-service-glue.h"
+
+
+#define NM_PPTP_PPP_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PPTP_PPP_SERVICE, NMPptpPppServicePrivate))
+
+typedef struct {
+	char username[100];
+	char domain[100];
+	char password[100];
+} NMPptpPppServicePrivate;
+
+enum {
+	PLUGIN_ALIVE,
+	PPP_STATE,
+	IP4_CONFIG,
+
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+NMPptpPppService *
+nm_pptp_ppp_service_new (void)
+{
+	DBusGConnection *connection;
+	DBusGProxy *proxy;
+	GError *error = NULL;
+	gboolean success = FALSE;
+	guint request_name_result;
+	GObject *object;
+
+	object = g_object_new (NM_TYPE_PPTP_PPP_SERVICE, NULL);
+
+	dbus_connection_set_change_sigpipe (TRUE);
+
+	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+	if (!connection) {
+		nm_warning ("Could not get the system bus.  Make sure "
+		            "the message bus daemon is running!  Message: %s",
+		            error->message);
+		g_error_free (error);
+		g_object_unref (object);
+		return NULL;
+	}
+
+	proxy = dbus_g_proxy_new_for_name (connection,
+								"org.freedesktop.DBus",
+								"/org/freedesktop/DBus",
+								"org.freedesktop.DBus");
+
+	if (dbus_g_proxy_call (proxy, "RequestName", &error,
+					   G_TYPE_STRING, NM_DBUS_SERVICE_PPTP_PPP,
+					   G_TYPE_UINT, 0,
+					   G_TYPE_INVALID,
+					   G_TYPE_UINT, &request_name_result,
+					   G_TYPE_INVALID)) {
+		dbus_g_connection_register_g_object (connection, NM_DBUS_PATH_PPTP_PPP, object);
+		success = TRUE;
+	} else {
+		nm_warning ("Could not register D-Bus service name.  Message: %s", error->message);
+		g_error_free (error);
+		g_object_unref (object);
+		object = NULL;
+	}
+
+	g_object_unref (proxy);
+	return (NMPptpPppService *) object;
+}
+
+static void
+nm_pptp_ppp_service_init (NMPptpPppService *self)
+{
+}
+
+static void
+finalize (GObject *object)
+{
+	NMPptpPppServicePrivate *priv = NM_PPTP_PPP_SERVICE_GET_PRIVATE (object);
+
+	/* Get rid of the cached username and password */
+	memset (priv->username, 0, sizeof (priv->username));
+	memset (priv->domain, 0, sizeof (priv->domain));
+	memset (priv->password, 0, sizeof (priv->password));
+}
+
+static void
+nm_pptp_ppp_service_class_init (NMPptpPppServiceClass *service_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (service_class);
+
+	g_type_class_add_private (service_class, sizeof (NMPptpPppServicePrivate));
+
+	/* virtual methods */
+	object_class->finalize = finalize;
+
+	/* Signals */
+	signals[PLUGIN_ALIVE] = 
+		g_signal_new ("plugin-alive", 
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMPptpPppServiceClass, plugin_alive),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE, 0);
+
+	signals[PPP_STATE] = 
+		g_signal_new ("ppp-state", 
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMPptpPppServiceClass, ppp_state),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	signals[IP4_CONFIG] = 
+		g_signal_new ("ip4-config", 
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMPptpPppServiceClass, ip4_config),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__POINTER,
+		              G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (service_class),
+									 &dbus_glib_nm_pptp_pppd_service_object_info);
+}
+
+static gboolean
+nm_pptp_ppp_service_cache_credentials (NMPptpPppService *self,
+                                       NMConnection *connection,
+                                       GError **error)
+{
+	NMPptpPppServicePrivate *priv = NM_PPTP_PPP_SERVICE_GET_PRIVATE (self);
+	NMSettingVPN *s_vpn;
+	const char *username, *password, *domain;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (connection != NULL, FALSE);
+
+	memset (priv->username, 0, sizeof (priv->username));
+	memset (priv->domain, 0, sizeof (priv->domain));
+	memset (priv->password, 0, sizeof (priv->password));
+
+	s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+	if (!s_vpn) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+		             "%s",
+		             "Could not find secrets (connection invalid, no vpn setting).");
+		return FALSE;
+	}
+
+	/* Username; try PPTP specific username first, then generic username */
+	username = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_USER);
+	if (username && strlen (username)) {
+		/* FIXME: This check makes about 0 sense. */
+		if (!username || !strlen (username)) {
+			g_set_error (error,
+			             NM_VPN_PLUGIN_ERROR,
+			             NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+			             "%s",
+			             "Invalid VPN username.");
+			return FALSE;
+		}
+	} else {
+		username = nm_setting_vpn_get_user_name (s_vpn);
+		if (!username || !strlen (username)) {
+			g_set_error (error,
+			             NM_VPN_PLUGIN_ERROR,
+			             NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+			             "%s",
+			             "Missing VPN username.");
+			return FALSE;
+		}
+	}
+
+	password = nm_setting_vpn_get_secret (s_vpn, NM_PPTP_KEY_PASSWORD);
+	if (!password || !strlen (password)) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+		             "%s",
+		             "Missing or invalid VPN password.");
+		return FALSE;
+	}
+
+	domain = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_DOMAIN);
+	if (domain && strlen (domain))
+		memcpy (priv->domain, domain, strlen (domain));
+
+	memcpy (priv->username, username, strlen (username));
+	memcpy (priv->password, password, strlen (password));
+	return TRUE;
+}
+
+static gboolean
+impl_pptp_service_need_secrets (NMPptpPppService *self,
+                                char **out_username,
+                                char **out_password,
+                                GError **error)
+{
+	NMPptpPppServicePrivate *priv = NM_PPTP_PPP_SERVICE_GET_PRIVATE (self);
+
+	g_signal_emit (G_OBJECT (self), signals[PLUGIN_ALIVE], 0);
+
+	if (!strlen (priv->username) || !strlen (priv->password)) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+		             "%s",
+		             "No cached credentials.");
+		goto error;
+	}
+
+	/* Success */
+	if (strlen (priv->domain))
+		*out_username = g_strdup_printf ("%s\\\\%s", priv->domain, priv->username);
+	else
+		*out_username = g_strdup (priv->username);
+	*out_password = g_strdup (priv->password);
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+static gboolean
+impl_pptp_service_set_state (NMPptpPppService *self,
+                             guint32 pppd_state,
+                             GError **err)
+{
+	g_signal_emit (G_OBJECT (self), signals[PLUGIN_ALIVE], 0);
+	g_signal_emit (G_OBJECT (self), signals[PPP_STATE], 0, pppd_state);
+	return TRUE;
+}
+
+static gboolean
+impl_pptp_service_set_ip4_config (NMPptpPppService *self,
+                                  GHashTable *config_hash,
+                                  GError **err)
+{
+	nm_info ("PPTP service (IP Config Get) reply received.");
+	g_signal_emit (G_OBJECT (self), signals[PLUGIN_ALIVE], 0);
+
+	/* Just forward the pppd plugin config up to our superclass; no need to modify it */
+	g_signal_emit (G_OBJECT (self), signals[IP4_CONFIG], 0, config_hash);
+
+	return TRUE;
+}
+
+
+/********************************************************/
+/* The VPN plugin service                               */
+/********************************************************/
+
+G_DEFINE_TYPE (NMPptpPlugin, nm_pptp_plugin, NM_TYPE_VPN_PLUGIN)
+
+typedef struct {
+	GPid pid;
+	guint32 ppp_timeout_handler;
+	NMPptpPppService *service;
+	NMConnection *connection;
+} NMPptpPluginPrivate;
+
+#define NM_PPTP_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PPTP_PLUGIN, NMPptpPluginPrivate))
+
+#define NM_PPTP_PPPD_PLUGIN PLUGINDIR "/nm-pptp-pppd-plugin.so"
+#define NM_PPTP_WAIT_PPPD 10000 /* 10 seconds */
+#define PPTP_SERVICE_SECRET_TRIES "pptp-service-secret-tries"
+
+typedef struct {
+	const char *name;
+	GType type;
+	gboolean required;
+} ValidProperty;
+
+static ValidProperty valid_properties[] = {
+	{ NM_PPTP_KEY_GATEWAY,           G_TYPE_STRING, TRUE },
+	{ NM_PPTP_KEY_USER,              G_TYPE_STRING, FALSE },
+	{ NM_PPTP_KEY_DOMAIN,            G_TYPE_STRING, FALSE },
+	{ NM_PPTP_KEY_REFUSE_EAP,        G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REFUSE_PAP,        G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REFUSE_CHAP,       G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REFUSE_MSCHAP,     G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REFUSE_MSCHAPV2,   G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REQUIRE_MPPE,      G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REQUIRE_MPPE_40,   G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_REQUIRE_MPPE_128,  G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_MPPE_STATEFUL,     G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_NOBSDCOMP,         G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_NODEFLATE,         G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_NO_VJ_COMP,        G_TYPE_BOOLEAN, FALSE },
+	{ NM_PPTP_KEY_LCP_ECHO_FAILURE,  G_TYPE_UINT, FALSE },
+	{ NM_PPTP_KEY_LCP_ECHO_INTERVAL, G_TYPE_UINT, FALSE },
+	{ NULL,                          G_TYPE_NONE,   FALSE }
+};
+
+static ValidProperty valid_secrets[] = {
+	{ NM_PPTP_KEY_PASSWORD,          G_TYPE_STRING, FALSE },
+	{ NULL,                          G_TYPE_NONE,   FALSE }
+};
+
+static gboolean
+validate_gateway (const char *gateway)
+{
+	const char *p = gateway;
+
+	if (!gateway || !strlen (gateway))
+		return FALSE;
+
+	/* Ensure it's a valid DNS name or IP address */
+	p = gateway;
+	while (*p) {
+		if (!isalnum (*p) && (*p != '-') && (*p != '.'))
+			return FALSE;
+		p++;
+	}
+	return TRUE;
+}
+
+typedef struct ValidateInfo {
+	ValidProperty *table;
+	GError **error;
+	gboolean have_items;
+} ValidateInfo;
+
+static void
+validate_one_property (const char *key, const char *value, gpointer user_data)
+{
+	ValidateInfo *info = (ValidateInfo *) user_data;
+	int i;
+
+	if (*(info->error))
+		return;
+
+	info->have_items = TRUE;
+
+	/* 'name' is the setting name; always allowed but unused */
+	if (!strcmp (key, NM_SETTING_NAME))
+		return;
+
+	for (i = 0; info->table[i].name; i++) {
+		ValidProperty prop = info->table[i];
+		long int tmp;
+
+		if (strcmp (prop.name, key))
+			continue;
+
+		switch (prop.type) {
+		case G_TYPE_STRING:
+			if (   !strcmp (prop.name, NM_PPTP_KEY_GATEWAY)
+			    && !validate_gateway (value)) {
+				g_set_error (info->error,
+				             NM_VPN_PLUGIN_ERROR,
+				             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+				             "invalid gateway '%s'",
+				             key);
+				return;
+			}
+			return; /* valid */
+		case G_TYPE_UINT:
+			errno = 0;
+			tmp = strtol (value, NULL, 10);
+			if (errno == 0)
+				return; /* valid */
+
+			g_set_error (info->error,
+			             NM_VPN_PLUGIN_ERROR,
+			             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+			             "invalid integer property '%s'",
+			             key);
+			break;
+		case G_TYPE_BOOLEAN:
+			if (!strcmp (value, "yes") || !strcmp (value, "no"))
+				return; /* valid */
+
+			g_set_error (info->error,
+			             NM_VPN_PLUGIN_ERROR,
+			             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+			             "invalid boolean property '%s' (not yes or no)",
+			             key);
+			break;
+		default:
+			g_set_error (info->error,
+			             NM_VPN_PLUGIN_ERROR,
+			             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+			             "unhandled property '%s' type %s",
+			             key, g_type_name (prop.type));
+			break;
+		}
+	}
+
+	/* Did not find the property from valid_properties or the type did not match */
+	if (!info->table[i].name) {
+		g_set_error (info->error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+		             "property '%s' invalid or not supported",
+		             key);
+	}
+}
+
+static gboolean
+nm_pptp_properties_validate (NMSettingVPN *s_vpn,
+                             GError **error)
+{
+	ValidateInfo info = { &valid_properties[0], error, FALSE };
+	int i;
+
+	nm_setting_vpn_foreach_data_item (s_vpn, validate_one_property, &info);
+	if (!info.have_items) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+		             "%s",
+		             "No VPN configuration options.");
+		return FALSE;
+	}
+
+	if (*error)
+		return FALSE;
+
+	/* Ensure required properties exist */
+	for (i = 0; valid_properties[i].name; i++) {
+		ValidProperty prop = valid_properties[i];
+		const char *value;
+
+		if (!prop.required)
+			continue;
+
+		value = nm_setting_vpn_get_data_item (s_vpn, prop.name);
+		if (!value || !strlen (value)) {
+			g_set_error (error,
+			             NM_VPN_PLUGIN_ERROR,
+			             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+			             "Missing required option '%s'.",
+			             prop.name);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+nm_pptp_secrets_validate (NMSettingVPN *s_vpn, GError **error)
+{
+	ValidateInfo info = { &valid_secrets[0], error, FALSE };
+
+	nm_setting_vpn_foreach_secret (s_vpn, validate_one_property, &info);
+	if (!info.have_items) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+		             "%s",
+		             "No VPN secrets!");
+		return FALSE;
+	}
+
+	return *error ? FALSE : TRUE;
+}
+
+static void
+pppd_watch_cb (GPid pid, gint status, gpointer user_data)
+{
+	NMPptpPlugin *plugin = NM_PPTP_PLUGIN (user_data);
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+	guint error = 0;
+
+	if (WIFEXITED (status)) {
+		error = WEXITSTATUS (status);
+		if (error != 0)
+			nm_warning ("pppd exited with error code %d", error);
+	}
+	else if (WIFSTOPPED (status))
+		nm_warning ("pppd stopped unexpectedly with signal %d", WSTOPSIG (status));
+	else if (WIFSIGNALED (status))
+		nm_warning ("pppd died with signal %d", WTERMSIG (status));
+	else
+		nm_warning ("pppd died from an unknown cause");
+
+	/* Reap child if needed. */
+	waitpid (priv->pid, NULL, WNOHANG);
+	priv->pid = 0;
+
+	/* Must be after data->state is set since signals use data->state */
+	switch (error) {
+	case 16:
+		/* hangup */
+		// FIXME: better failure reason
+		nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
+		break;
+	case 2:
+		/* Couldn't log in due to bad user/pass */
+		nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
+		break;
+	case 1:
+		/* Other error (couldn't bind to address, etc) */
+		nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
+		break;
+	default:
+		break;
+	}
+
+	nm_vpn_plugin_set_state (NM_VPN_PLUGIN (plugin), NM_VPN_SERVICE_STATE_STOPPED);
+}
+
+static inline const char *
+nm_find_pppd (void)
+{
+	static const char *pppd_binary_paths[] =
+		{
+			"/sbin/pppd",
+			"/usr/sbin/pppd",
+			"/usr/local/sbin/pppd",
+			NULL
+		};
+
+	const char  **pppd_binary = pppd_binary_paths;
+
+	while (*pppd_binary != NULL) {
+		if (g_file_test (*pppd_binary, G_FILE_TEST_EXISTS))
+			break;
+		pppd_binary++;
+	}
+
+	return *pppd_binary;
+}
+
+static inline const char *
+nm_find_pptp (void)
+{
+	static const char *pptp_binary_paths[] =
+		{
+			"/sbin/pptp",
+			"/usr/sbin/pptp",
+			"/usr/local/sbin/pptp",
+			NULL
+		};
+
+	const char  **pptp_binary = pptp_binary_paths;
+
+	while (*pptp_binary != NULL) {
+		if (g_file_test (*pptp_binary, G_FILE_TEST_EXISTS))
+			break;
+		pptp_binary++;
+	}
+
+	return *pptp_binary;
+}
+
+static gboolean
+pppd_timed_out (gpointer user_data)
+{
+	NMPptpPlugin *plugin = NM_PPTP_PLUGIN (user_data);
+
+	nm_warning ("Looks like pppd didn't initialize our dbus module");
+	nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT);
+
+	return FALSE;
+}
+
+static void
+free_pppd_args (GPtrArray *args)
+{
+	int i;
+
+	if (!args)
+		return;
+
+	for (i = 0; i < args->len; i++)
+		g_free (g_ptr_array_index (args, i));
+	g_ptr_array_free (args, TRUE);
+}
+
+static GPtrArray *
+construct_pppd_args (NMPptpPlugin *plugin,
+                     NMSettingVPN *s_vpn,
+                     const char *pppd,
+                     GError **error)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+	NMPptpPppServicePrivate *service_priv = NULL;
+	GPtrArray *args = NULL;
+	const char *value, *pptp_binary;
+	char *ipparam, *tmp;
+
+	pptp_binary = nm_find_pptp ();
+	if (!pptp_binary) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+		             "%s",
+		             "Could not find pptp client binary.");
+		return FALSE;
+	}
+
+	args = g_ptr_array_new ();
+	g_ptr_array_add (args, (gpointer) g_strdup (pppd));
+
+	/* PPTP options */
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_GATEWAY);
+	if (!value || !strlen (value)) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+		             "%s",
+		             "Missing VPN gateway.");
+		goto error;
+	}
+
+	ipparam = g_strdup_printf ("nm-pptp-service-%d", getpid ());
+
+	g_ptr_array_add (args, (gpointer) g_strdup ("pty"));
+	tmp = g_strdup_printf ("%s %s --nolaunchpppd --logstring %s", pptp_binary, value, ipparam);
+	g_ptr_array_add (args, (gpointer) tmp);
+
+	if (getenv ("NM_PPP_DEBUG"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("debug"));
+
+	/* PPP options */
+	g_ptr_array_add (args, (gpointer) g_strdup ("ipparam"));
+	g_ptr_array_add (args, (gpointer) ipparam);
+
+	g_ptr_array_add (args, (gpointer) g_strdup ("nodetach"));
+	g_ptr_array_add (args, (gpointer) g_strdup ("lock"));
+	g_ptr_array_add (args, (gpointer) g_strdup ("usepeerdns"));
+	g_ptr_array_add (args, (gpointer) g_strdup ("noipdefault"));
+	g_ptr_array_add (args, (gpointer) g_strdup ("nodefaultroute"));
+
+	if (priv->service)
+		service_priv = NM_PPTP_PPP_SERVICE_GET_PRIVATE (priv->service);
+	if (service_priv && strlen (service_priv->username)) {
+		g_ptr_array_add (args, (gpointer) g_strdup ("user"));
+		g_ptr_array_add (args, (gpointer) g_strdup (service_priv->username));
+	}
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REFUSE_EAP);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("refuse-eap"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REFUSE_PAP);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("refuse-pap"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REFUSE_CHAP);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("refuse-chap"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REFUSE_MSCHAP);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("refuse-mschap"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REFUSE_MSCHAPV2);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("refuse-mschap-v2"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REQUIRE_MPPE);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("require-mppe"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REQUIRE_MPPE_40);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("require-mppe-40"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_REQUIRE_MPPE_128);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("require-mppe-128"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_MPPE_STATEFUL);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("mppe-stateful"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_NOBSDCOMP);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("nobsdcomp"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_NODEFLATE);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("nodeflate"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_NO_VJ_COMP);
+	if (value && !strcmp (value, "yes"))
+		g_ptr_array_add (args, (gpointer) g_strdup ("novj"));
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_LCP_ECHO_FAILURE);
+	if (value && strlen (value)) {
+		long int tmp_int;
+
+		/* Convert to integer and then back to string for security's sake
+		 * because strtol ignores some leading and trailing characters.
+		 */
+		errno = 0;
+		tmp_int = strtol (value, NULL, 10);
+		if (errno == 0) {
+			g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-failure"));
+			g_ptr_array_add (args, (gpointer) g_strdup_printf ("%ld", tmp_int));
+		} else {
+			nm_warning ("failed to convert lcp-echo-failure value '%s'", value);
+		}
+	} else {
+		g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-failure"));
+		g_ptr_array_add (args, (gpointer) g_strdup ("0"));
+	}
+
+	value = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_LCP_ECHO_INTERVAL);
+	if (value && strlen (value)) {
+		long int tmp_int;
+
+		/* Convert to integer and then back to string for security's sake
+		 * because strtol ignores some leading and trailing characters.
+		 */
+		errno = 0;
+		tmp_int = strtol (value, NULL, 10);
+		if (errno == 0) {
+			g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-interval"));
+			g_ptr_array_add (args, (gpointer) g_strdup_printf ("%ld", tmp_int));
+		} else {
+			nm_warning ("failed to convert lcp-echo-interval value '%s'", value);
+		}
+	} else {
+		g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-interval"));
+		g_ptr_array_add (args, (gpointer) g_strdup ("0"));
+	}
+
+	g_ptr_array_add (args, (gpointer) g_strdup ("plugin"));
+	g_ptr_array_add (args, (gpointer) g_strdup (NM_PPTP_PPPD_PLUGIN));
+
+	g_ptr_array_add (args, NULL);
+
+	return args;
+
+error:
+	free_pppd_args (args);
+	return FALSE;
+}
+
+static gboolean
+nm_pptp_start_pppd_binary (NMPptpPlugin *plugin,
+                           NMSettingVPN *s_vpn,
+                           GError **error)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+	GPid pid;
+	const char *pppd_binary;
+	GPtrArray *pppd_argv;
+
+	pppd_binary = nm_find_pppd ();
+	if (!pppd_binary) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+		             "%s",
+		             "Could not find the pppd binary.");
+		return FALSE;
+	}
+
+	pppd_argv = construct_pppd_args (plugin, s_vpn, pppd_binary, error);
+	if (!pppd_argv)
+		return FALSE;
+
+	if (!g_spawn_async (NULL, (char **) pppd_argv->pdata, NULL,
+	                    G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, error)) {
+		g_ptr_array_free (pppd_argv, TRUE);
+		return FALSE;
+	}
+	free_pppd_args (pppd_argv);
+
+	nm_info ("pppd started with pid %d", pid);
+
+	NM_PPTP_PLUGIN_GET_PRIVATE (plugin)->pid = pid;
+	g_child_watch_add (pid, pppd_watch_cb, plugin);
+
+	priv->ppp_timeout_handler = g_timeout_add (NM_PPTP_WAIT_PPPD, pppd_timed_out, plugin);
+
+	return TRUE;
+}
+
+static void
+remove_timeout_handler (NMPptpPlugin *plugin)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+	
+	if (priv->ppp_timeout_handler) {
+		g_source_remove (priv->ppp_timeout_handler);
+		priv->ppp_timeout_handler = 0;
+	}
+}
+
+static void
+service_plugin_alive_cb (NMPptpPppService *service,
+                         NMPptpPlugin *plugin)
+{
+	remove_timeout_handler (plugin);
+}
+
+static void
+service_ppp_state_cb (NMPptpPppService *service,
+                      guint32 ppp_state,
+                      NMPptpPlugin *plugin)
+{
+	NMVPNServiceState plugin_state = nm_vpn_plugin_get_state (NM_VPN_PLUGIN (plugin));
+
+	switch (ppp_state) {
+	case NM_PPP_STATUS_DEAD:
+	case NM_PPP_STATUS_DISCONNECT:
+		if (plugin_state == NM_VPN_SERVICE_STATE_STARTED)
+			nm_vpn_plugin_disconnect (NM_VPN_PLUGIN (plugin), NULL);
+		else if (plugin_state == NM_VPN_SERVICE_STATE_STARTING)
+			nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+nm_gvalue_destroy (gpointer data)
+{
+	g_value_unset ((GValue *) data);
+	g_slice_free (GValue, data);
+}
+
+static GValue *
+nm_gvalue_dup (const GValue *value)
+{
+	GValue *dup;
+
+	dup = g_slice_new0 (GValue);
+	g_value_init (dup, G_VALUE_TYPE (value));
+	g_value_copy (value, dup);
+
+	return dup;
+}
+
+static void
+copy_hash (gpointer key, gpointer value, gpointer user_data)
+{
+	g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), nm_gvalue_dup ((GValue *) value));
+}
+
+static GValue *
+get_pptp_gw_address_as_gvalue (NMConnection *connection)
+{
+	NMSettingVPN *s_vpn;
+	const char *tmp;
+	GValue *value;
+	struct in_addr addr;
+
+	s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+	if (!s_vpn) {
+		nm_warning ("couldn't get VPN setting");
+		return NULL;
+	}
+
+	tmp = nm_setting_vpn_get_data_item (s_vpn, NM_PPTP_KEY_GATEWAY);
+	if (!tmp || !strlen (tmp)) {
+		nm_warning ("couldn't get PPTP VPN gateway IP address");
+		return NULL;
+	}
+	
+	errno = 0;
+	if (inet_pton (AF_INET, tmp, &addr) <= 0) {
+		nm_warning ("couldn't convert PPTP VPN gateway IP address '%s' (%d)", tmp, errno);
+		return NULL;
+	}
+	
+	value = g_slice_new0 (GValue);
+	g_value_init (value, G_TYPE_UINT);
+	g_value_set_uint (value, (guint32) addr.s_addr);
+
+	return value;
+}
+
+static void
+service_ip4_config_cb (NMPptpPppService *service,
+                       GHashTable *config_hash,
+                       NMPptpPlugin *plugin)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+	GHashTable *hash;
+	GValue *value;
+
+	hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy);
+	g_hash_table_foreach (config_hash, copy_hash, hash);
+
+	/* Insert the external VPN gateway into the table, which the pppd plugin
+	 * simply doesn't know about.
+	 */
+	value = get_pptp_gw_address_as_gvalue (priv->connection);
+	if (value)
+		g_hash_table_insert (hash, g_strdup (NM_PPTP_KEY_GATEWAY), value);
+
+	nm_vpn_plugin_set_ip4_config (NM_VPN_PLUGIN (plugin), hash);
+
+	g_hash_table_destroy (hash);
+}
+
+static gboolean
+real_connect (NMVPNPlugin   *plugin,
+              NMConnection  *connection,
+              GError       **error)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+	NMSettingVPN *s_vpn;
+
+	s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+	g_assert (s_vpn);
+
+	if (!nm_pptp_properties_validate (s_vpn, error))
+		return FALSE;
+
+	if (!nm_pptp_secrets_validate (s_vpn, error))
+		return FALSE;
+
+	/* Start our pppd plugin helper service */
+	if (priv->service)
+		g_object_unref (priv->service);
+	if (priv->connection) {
+		g_object_unref (priv->connection);
+		priv->connection = NULL;
+	}
+
+	priv->service = nm_pptp_ppp_service_new ();
+	if (!priv->service) {
+		g_set_error (error,
+		             NM_VPN_PLUGIN_ERROR,
+		             NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+		             "%s",
+		             "Could not start pppd plugin helper service.");
+		return FALSE;
+	}
+
+	priv->connection = g_object_ref (connection);
+
+	g_signal_connect (G_OBJECT (priv->service), "plugin-alive", G_CALLBACK (service_plugin_alive_cb), plugin);
+	g_signal_connect (G_OBJECT (priv->service), "ppp-state", G_CALLBACK (service_ppp_state_cb), plugin);
+	g_signal_connect (G_OBJECT (priv->service), "ip4-config", G_CALLBACK (service_ip4_config_cb), plugin);
+
+	/* Cache the username and password so we can relay the secrets to the pppd
+	 * plugin when it asks for them.
+	 */
+	if (!nm_pptp_ppp_service_cache_credentials (priv->service, connection, error))
+		return FALSE;
+
+	if (!nm_pptp_start_pppd_binary (NM_PPTP_PLUGIN (plugin), s_vpn, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+real_need_secrets (NMVPNPlugin *plugin,
+                   NMConnection *connection,
+                   char **setting_name,
+                   GError **error)
+{
+	NMSettingVPN *s_vpn;
+
+	g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+	s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+
+	if (!nm_setting_vpn_get_secret (s_vpn, NM_PPTP_KEY_PASSWORD)) {
+		*setting_name = NM_SETTING_VPN_SETTING_NAME;
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+ensure_killed (gpointer data)
+{
+	int pid = GPOINTER_TO_INT (data);
+
+	if (kill (pid, 0) == 0)
+		kill (pid, SIGKILL);
+
+	return FALSE;
+}
+
+static gboolean
+real_disconnect (NMVPNPlugin   *plugin,
+			  GError       **err)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (plugin);
+
+	if (priv->pid) {
+		if (kill (priv->pid, SIGTERM) == 0)
+			g_timeout_add (2000, ensure_killed, GINT_TO_POINTER (priv->pid));
+		else
+			kill (priv->pid, SIGKILL);
+
+		nm_info ("Terminated ppp daemon with PID %d.", priv->pid);
+		priv->pid = 0;
+	}
+
+	if (priv->connection) {
+		g_object_unref (priv->connection);
+		priv->connection = NULL;
+	}
+
+	if (priv->service) {
+		g_object_unref (priv->service);
+		priv->service = NULL;
+	}
+
+	return TRUE;
+}
+
+static void
+state_changed_cb (GObject *object, NMVPNServiceState state, gpointer user_data)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (object);
+
+	switch (state) {
+	case NM_VPN_SERVICE_STATE_STARTED:
+		remove_timeout_handler (NM_PPTP_PLUGIN (object));
+		break;
+	case NM_VPN_SERVICE_STATE_UNKNOWN:
+	case NM_VPN_SERVICE_STATE_INIT:
+	case NM_VPN_SERVICE_STATE_SHUTDOWN:
+	case NM_VPN_SERVICE_STATE_STOPPING:
+	case NM_VPN_SERVICE_STATE_STOPPED:
+		remove_timeout_handler (NM_PPTP_PLUGIN (object));
+		if (priv->connection) {
+			g_object_unref (priv->connection);
+			priv->connection = NULL;
+		}
+		if (priv->service) {
+			g_object_unref (priv->service);
+			priv->service = NULL;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMPptpPluginPrivate *priv = NM_PPTP_PLUGIN_GET_PRIVATE (object);
+
+	if (priv->connection)
+		g_object_unref (priv->connection);
+
+	if (priv->service)
+		g_object_unref (priv->service);
+
+	G_OBJECT_CLASS (nm_pptp_plugin_parent_class)->dispose (object);
+}
+
+static void
+nm_pptp_plugin_init (NMPptpPlugin *plugin)
+{
+}
+
+static void
+nm_pptp_plugin_class_init (NMPptpPluginClass *pptp_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (pptp_class);
+	NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS (pptp_class);
+
+	g_type_class_add_private (object_class, sizeof (NMPptpPluginPrivate));
+
+	/* virtual methods */
+	object_class->dispose = dispose;
+	parent_class->connect    = real_connect;
+	parent_class->need_secrets = real_need_secrets;
+	parent_class->disconnect = real_disconnect;
+}
+
+NMPptpPlugin *
+nm_pptp_plugin_new (void)
+{
+	NMPptpPlugin *plugin;
+
+	plugin = g_object_new (NM_TYPE_PPTP_PLUGIN,
+	                       NM_VPN_PLUGIN_DBUS_SERVICE_NAME,
+	                       NM_DBUS_SERVICE_PPTP,
+	                       NULL);
+	if (plugin)
+		g_signal_connect (G_OBJECT (plugin), "state-changed", G_CALLBACK (state_changed_cb), NULL);
+	return plugin;
+}
+
+static void
+quit_mainloop (NMPptpPlugin *plugin, gpointer user_data)
+{
+	g_main_loop_quit ((GMainLoop *) user_data);
+}
+
+int
+main (int argc, char *argv[])
+{
+	NMPptpPlugin *plugin;
+	GMainLoop *main_loop;
+
+	g_type_init ();
+
+	plugin = nm_pptp_plugin_new ();
+	if (!plugin)
+		exit (EXIT_FAILURE);
+
+	main_loop = g_main_loop_new (NULL, FALSE);
+
+	g_signal_connect (plugin, "quit",
+				   G_CALLBACK (quit_mainloop),
+				   main_loop);
+
+	g_main_loop_run (main_loop);
+
+	g_main_loop_unref (main_loop);
+	g_object_unref (plugin);
+
+	exit (EXIT_SUCCESS);
+}

Added: trunk/src/nm-pptp-service.h
==============================================================================
--- (empty file)
+++ trunk/src/nm-pptp-service.h	Thu Dec 11 19:53:06 2008
@@ -0,0 +1,82 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-pptp-service - PPTP VPN integration with NetworkManager
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef NM_PPTP_PLUGIN_H
+#define NM_PPTP_PLUGIN_H
+
+#include <glib/gtypes.h>
+#include <glib-object.h>
+#include <nm-vpn-plugin.h>
+
+#define NM_TYPE_PPTP_PLUGIN            (nm_pptp_plugin_get_type ())
+#define NM_PPTP_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PPTP_PLUGIN, NMPptpPlugin))
+#define NM_PPTP_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PPTP_PLUGIN, NMPptpPluginClass))
+#define NM_IS_PPTP_PLUGIN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PPTP_PLUGIN))
+#define NM_IS_PPTP_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_PPTP_PLUGIN))
+#define NM_PPTP_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PPTP_PLUGIN, NMPptpPluginClass))
+
+/* For the pppd plugin <-> VPN plugin service */
+#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
+
+#define NM_DBUS_SERVICE_PPTP_PPP    "org.freedesktop.NetworkManager.pptp-ppp"
+#define NM_DBUS_PATH_PPTP_PPP       "/org/freedesktop/NetworkManager/pptp/ppp"
+#define NM_DBUS_INTERFACE_PPTP_PPP  "org.freedesktop.NetworkManager.pptp.ppp"
+
+
+/* For the NM <-> VPN plugin service */
+#define NM_DBUS_SERVICE_PPTP    "org.freedesktop.NetworkManager.pptp"
+#define NM_DBUS_INTERFACE_PPTP  "org.freedesktop.NetworkManager.pptp"
+#define NM_DBUS_PATH_PPTP       "/org/freedesktop/NetworkManager/pptp"
+
+#define NM_PPTP_KEY_GATEWAY           "gateway"
+#define NM_PPTP_KEY_USER              "user"
+#define NM_PPTP_KEY_PASSWORD          "password"
+#define NM_PPTP_KEY_DOMAIN            "domain"
+#define NM_PPTP_KEY_REFUSE_EAP        "refuse-eap"
+#define NM_PPTP_KEY_REFUSE_PAP        "refuse-pap"
+#define NM_PPTP_KEY_REFUSE_CHAP       "refuse-chap"
+#define NM_PPTP_KEY_REFUSE_MSCHAP     "refuse-mschap"
+#define NM_PPTP_KEY_REFUSE_MSCHAPV2   "refuse-mschapv2"
+#define NM_PPTP_KEY_REQUIRE_MPPE      "require-mppe"
+#define NM_PPTP_KEY_REQUIRE_MPPE_40   "require-mppe-40"
+#define NM_PPTP_KEY_REQUIRE_MPPE_128  "require-mppe-128"
+#define NM_PPTP_KEY_MPPE_STATEFUL     "mppe-stateful"
+#define NM_PPTP_KEY_NOBSDCOMP         "nobsdcomp"
+#define NM_PPTP_KEY_NODEFLATE         "nodeflate"
+#define NM_PPTP_KEY_NO_VJ_COMP        "no-vj-comp"
+#define NM_PPTP_KEY_LCP_ECHO_FAILURE  "lcp-echo-failure"
+#define NM_PPTP_KEY_LCP_ECHO_INTERVAL "lcp-echo-interval"
+
+
+typedef struct {
+	NMVPNPlugin parent;
+} NMPptpPlugin;
+
+typedef struct {
+	NMVPNPluginClass parent;
+} NMPptpPluginClass;
+
+GType nm_pptp_plugin_get_type (void);
+
+NMPptpPlugin *nm_pptp_plugin_new (void);
+
+#endif /* NM_PPTP_PLUGIN_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]