1/* $Id$ */
2
3/***
4  This file is part of avahi.
5
6  avahi is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Lesser General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  avahi is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14  Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with avahi; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  USA.
20***/
21
22using System;
23using System.Collections;
24using System.Runtime.InteropServices;
25using System.Text;
26
27namespace Avahi
28{
29    internal delegate void DomainBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
30                                                  IntPtr domain, LookupResultFlags flags, IntPtr userdata);
31
32    public enum DomainBrowserType {
33        Browse,
34        BrowseDefault,
35        Register,
36        RegisterDefault,
37        BrowseLegacy
38    }
39
40    public struct DomainInfo
41    {
42        public int NetworkInterface;
43        public Protocol Protocol;
44        public string Domain;
45        public LookupResultFlags Flags;
46    }
47
48    public class DomainInfoArgs : EventArgs
49    {
50        private DomainInfo domain;
51
52        public DomainInfo Domain
53        {
54            get { return domain; }
55        }
56
57        public DomainInfoArgs (DomainInfo domain)
58        {
59            this.domain = domain;
60        }
61    }
62
63    public delegate void DomainInfoHandler (object o, DomainInfoArgs args);
64
65    public class DomainBrowser : BrowserBase, IDisposable
66    {
67        private IntPtr handle;
68        private ArrayList infos = new ArrayList ();
69        private Client client;
70        private int iface;
71        private Protocol proto;
72        private string domain;
73        private DomainBrowserType btype;
74        private LookupFlags flags;
75        private DomainBrowserCallback cb;
76
77        private ArrayList addListeners = new ArrayList ();
78        private ArrayList removeListeners = new ArrayList ();
79
80        [DllImport ("avahi-client")]
81        private static extern IntPtr avahi_domain_browser_new (IntPtr client, int iface, int proto,
82                                                               byte[] domain, int btype, LookupFlags flags,
83                                                               DomainBrowserCallback cb,
84                                                               IntPtr userdata);
85
86        [DllImport ("avahi-client")]
87        private static extern void avahi_domain_browser_free (IntPtr handle);
88
89        public event DomainInfoHandler DomainAdded
90        {
91            add {
92                addListeners.Add (value);
93                Start ();
94            }
95            remove {
96                addListeners.Remove (value);
97                Stop (false);
98            }
99        }
100
101        public event DomainInfoHandler DomainRemoved
102        {
103            add {
104                removeListeners.Add (value);
105                Start ();
106            }
107            remove {
108                removeListeners.Remove (value);
109                Stop (false);
110            }
111        }
112
113        public DomainInfo[] Domains
114        {
115            get { return (DomainInfo[]) infos.ToArray (typeof (DomainInfo)); }
116        }
117
118        public DomainBrowser (Client client) : this (client, -1, Protocol.Unspecified, client.DomainName,
119                                                     DomainBrowserType.Browse, LookupFlags.None) {
120        }
121
122        public DomainBrowser (Client client, int iface, Protocol proto, string domain,
123                              DomainBrowserType btype, LookupFlags flags)
124        {
125            this.client = client;
126            this.iface = iface;
127            this.proto = proto;
128            this.domain = domain;
129            this.btype = btype;
130            this.flags = flags;
131            cb = OnDomainBrowserCallback;
132        }
133
134        ~DomainBrowser ()
135        {
136            Dispose ();
137        }
138
139        public void Dispose ()
140        {
141            Stop (true);
142        }
143
144        private void Start ()
145        {
146            if (client.Handle == IntPtr.Zero && handle != IntPtr.Zero ||
147                (addListeners.Count == 0 && removeListeners.Count == 0))
148                return;
149
150            lock (client) {
151                handle = avahi_domain_browser_new (client.Handle, iface, (int) proto,
152                                                   Utility.StringToBytes (domain), (int) btype, flags,
153                                                   cb, IntPtr.Zero);
154
155                if (handle == IntPtr.Zero)
156                    client.ThrowError ();
157            }
158        }
159
160        private void Stop (bool force)
161        {
162            if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
163                (force || (addListeners.Count == 0 && removeListeners.Count == 0))) {
164                lock (client) {
165                    avahi_domain_browser_free (handle);
166                    handle = IntPtr.Zero;
167                }
168            }
169        }
170
171        private void OnDomainBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
172                                              IntPtr domain, LookupResultFlags flags, IntPtr userdata)
173        {
174
175            DomainInfo info;
176            info.NetworkInterface = iface;
177            info.Protocol = proto;
178            info.Domain = Utility.PtrToString (domain);
179            info.Flags = flags;
180
181            switch (bevent) {
182            case BrowserEvent.Added:
183                infos.Add (info);
184
185                foreach (DomainInfoHandler handler in addListeners)
186                    handler (this, new DomainInfoArgs (info));
187                break;
188            case BrowserEvent.Removed:
189                infos.Remove (info);
190
191                foreach (DomainInfoHandler handler in removeListeners)
192                    handler (this, new DomainInfoArgs (info));
193                break;
194            default:
195                EmitBrowserEvent (bevent);
196                break;
197            }
198        }
199    }
200}
201