Merge lp:~sergiusens/account-polld/qtcontact into lp:~ubuntu-push-hackers/account-polld/trunk

Proposed by Sergio Schvezov
Status: Superseded
Proposed branch: lp:~sergiusens/account-polld/qtcontact
Merge into: lp:~ubuntu-push-hackers/account-polld/trunk
Prerequisite: lp:~sergiusens/account-polld/icon_fixes
Diff against target: 850 lines (+546/-94)
12 files modified
accounts/accounts.go (+0/-10)
cmd/account-polld/account_manager.go (+47/-46)
cmd/account-polld/main.go (+70/-37)
cmd/qtcontact-test/main.go (+37/-0)
debian/control (+3/-0)
plugins/gmail/gmail.go (+5/-1)
pollbus/bus.go (+94/-0)
qtcontact/contacts.go (+68/-0)
qtcontact/qtcontacts.cpp (+69/-0)
qtcontact/qtcontacts.h (+32/-0)
qtcontact/qtcontacts.hpp (+33/-0)
qtcontact/qtcontacts.moc (+88/-0)
To merge this branch: bzr merge lp:~sergiusens/account-polld/qtcontact
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
Roberto Alsina (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+228969@code.launchpad.net

This proposal has been superseded by a proposal from 2014-08-25.

Commit message

Adding gmail avatar's through QtContacts

Description of the change

This seems to work standalone but falls short when integrated; I am thinking it's a Qt versus glib mainloop problem here.

I haven't done this in callback mode yet; not sure if it's worth it; please advice.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Roberto Alsina (ralsina) :
review: Approve
39. By Sergio Schvezov

Merging poll

Revision history for this message
Manuel de la Peña (mandel) :
review: Approve

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'accounts/accounts.go'
2--- accounts/accounts.go 2014-07-25 20:09:20 +0000
3+++ accounts/accounts.go 2014-08-25 14:55:20 +0000
4@@ -50,18 +50,10 @@
5 }
6
7 var (
8- mainLoopOnce sync.Once
9 authChannels = make(map[*C.AccountWatcher]chan<- AuthData)
10 authChannelsLock sync.Mutex
11 )
12
13-func startMainLoop() {
14- mainLoopOnce.Do(func() {
15- mainLoop := C.g_main_loop_new(nil, C.gboolean(1))
16- go C.g_main_loop_run(mainLoop)
17- })
18-}
19-
20 // NewWatcher creates a new account watcher for the given service names
21 func NewWatcher(serviceType string) *Watcher {
22 w := new(Watcher)
23@@ -75,8 +67,6 @@
24 authChannels[w.watcher] = ch
25 authChannelsLock.Unlock()
26
27- startMainLoop()
28-
29 return w
30 }
31
32
33=== modified file 'cmd/account-polld/account_manager.go'
34--- cmd/account-polld/account_manager.go 2014-08-05 20:14:24 +0000
35+++ cmd/account-polld/account_manager.go 2014-08-25 14:55:20 +0000
36@@ -19,8 +19,6 @@
37
38 import (
39 "log"
40- "os"
41- "strconv"
42 "time"
43
44 "launchpad.net/account-polld/accounts"
45@@ -29,62 +27,74 @@
46 )
47
48 type AccountManager struct {
49- watcher *accounts.Watcher
50- authData accounts.AuthData
51- plugin plugins.Plugin
52- interval time.Duration
53- postWatch chan *PostWatch
54- authChan chan accounts.AuthData
55+ watcher *accounts.Watcher
56+ authData accounts.AuthData
57+ plugin plugins.Plugin
58+ interval time.Duration
59+ postWatch chan *PostWatch
60+ authChan chan accounts.AuthData
61+ doneChan chan error
62+ penaltyCount int
63 }
64
65 var (
66- pollInterval = time.Duration(5 * time.Minute)
67- maxInterval = time.Duration(20 * time.Minute)
68+ pollTimeout = time.Duration(30 * time.Second)
69+ bootstrapPollTimeout = time.Duration(5 * time.Minute)
70+ maxCounter = 4
71 )
72
73-func init() {
74- if intervalEnv := os.Getenv("ACCOUNT_POLLD_POLL_INTERVAL_MINUTES"); intervalEnv != "" {
75- if interval, err := strconv.ParseInt(intervalEnv, 0, 0); err == nil {
76- pollInterval = time.Duration(interval) * time.Minute
77- }
78- }
79-}
80-
81 func NewAccountManager(watcher *accounts.Watcher, postWatch chan *PostWatch, plugin plugins.Plugin) *AccountManager {
82 return &AccountManager{
83 watcher: watcher,
84 plugin: plugin,
85- interval: pollInterval,
86 postWatch: postWatch,
87 authChan: make(chan accounts.AuthData, 1),
88+ doneChan: make(chan error, 1),
89 }
90 }
91
92 func (a *AccountManager) Delete() {
93 close(a.authChan)
94+ close(a.doneChan)
95 }
96
97-func (a *AccountManager) Loop() {
98- var ok bool
99- if a.authData, ok = <-a.authChan; !ok {
100+func (a *AccountManager) Poll(bootstrap bool) {
101+ if !a.authData.Enabled {
102+ var ok bool
103+ if a.authData, ok = <-a.authChan; !ok {
104+ log.Println("Account", a.authData.AccountId, "no longer enabled")
105+ return
106+ }
107+ }
108+ if a.penaltyCount > 0 {
109+ log.Printf("Leaving poll for account %d as penaly count is %d", a.authData.AccountId, a.penaltyCount)
110+ a.penaltyCount--
111 return
112 }
113- // This is an initial out of loop poll
114- a.poll()
115-L:
116- for {
117- log.Println("Next poll set to", a.interval, "for account", a.authData.AccountId)
118- select {
119- case <-time.After(a.interval):
120- a.poll()
121- case a.authData, ok = <-a.authChan:
122- if !ok {
123- break L
124+ timeout := pollTimeout
125+ if bootstrap {
126+ timeout = bootstrapPollTimeout
127+ }
128+
129+ log.Printf("Starting poll for account %d", a.authData.AccountId)
130+ go a.poll()
131+
132+ select {
133+ case <-time.After(timeout):
134+ log.Println("Poll for account", a.authData.AccountId, "has timed out out after", timeout)
135+ a.penaltyCount++
136+ case err := <-a.doneChan:
137+ if err == nil {
138+ log.Println("Poll for account", a.authData.AccountId, "was successful")
139+ a.penaltyCount = 0
140+ } else {
141+ log.Println("Poll for account", a.authData.AccountId, "has failed:", err)
142+ if a.penaltyCount < maxCounter {
143+ a.penaltyCount++
144 }
145- a.poll()
146 }
147 }
148- log.Printf("Ending poll loop for account %d", a.authData.AccountId)
149+ log.Printf("Ending poll for account %d", a.authData.AccountId)
150 }
151
152 func (a *AccountManager) poll() {
153@@ -96,11 +106,6 @@
154 return
155 }
156
157- if !a.authData.Enabled {
158- log.Println("Account", a.authData.AccountId, "no longer enabled")
159- return
160- }
161-
162 if a.authData.Error != nil {
163 log.Println("Account", a.authData.AccountId, "failed to authenticate:", a.authData.Error)
164 return
165@@ -108,10 +113,6 @@
166
167 if n, err := a.plugin.Poll(&a.authData); err != nil {
168 log.Print("Error while polling ", a.authData.AccountId, ": ", err)
169- // penalizing the next poll
170- if a.interval.Minutes() < maxInterval.Minutes() {
171- a.interval += pollInterval
172- }
173
174 // If the error indicates that the authentication
175 // token has expired, request reauthentication and
176@@ -120,13 +121,13 @@
177 a.watcher.Refresh(a.authData.AccountId)
178 a.authData.Enabled = false
179 }
180+ a.doneChan <- err
181 } else {
182 log.Println("Account", a.authData.AccountId, "has", len(n), "updates to report")
183 if len(n) > 0 {
184 a.postWatch <- &PostWatch{messages: n, appId: a.plugin.ApplicationId()}
185 }
186- // on success we reset the timeout to the default interval
187- a.interval = pollInterval
188+ a.doneChan <- nil
189 }
190 }
191
192
193=== modified file 'cmd/account-polld/main.go'
194--- cmd/account-polld/main.go 2014-08-08 20:11:14 +0000
195+++ cmd/account-polld/main.go 2014-08-25 14:55:20 +0000
196@@ -21,6 +21,7 @@
197 "encoding/json"
198 "fmt"
199 "strings"
200+ "sync"
201
202 "log"
203
204@@ -30,6 +31,8 @@
205 "launchpad.net/account-polld/plugins/facebook"
206 "launchpad.net/account-polld/plugins/gmail"
207 "launchpad.net/account-polld/plugins/twitter"
208+ "launchpad.net/account-polld/pollbus"
209+ "launchpad.net/account-polld/qtcontact"
210 "launchpad.net/go-dbus/v1"
211 )
212
213@@ -52,7 +55,16 @@
214 POSTAL_OBJECT_PATH_PART = "/com/ubuntu/Postal/"
215 )
216
217+var mainLoopOnce sync.Once
218+
219 func init() {
220+ startMainLoop()
221+}
222+
223+func startMainLoop() {
224+ mainLoopOnce.Do(func() {
225+ go qtcontact.MainLoopStart()
226+ })
227 }
228
229 func main() {
230@@ -64,52 +76,73 @@
231 gettext.Textdomain("account-polld")
232 gettext.BindTextdomain("account-polld", "/usr/share/locale")
233
234- if bus, err := dbus.Connect(dbus.SessionBus); err != nil {
235+ bus, err := dbus.Connect(dbus.SessionBus)
236+ if err != nil {
237 log.Fatal("Cannot connect to bus", err)
238- } else {
239- go postOffice(bus, postWatch)
240- }
241-
242- go monitorAccounts(postWatch)
243+ }
244+
245+ pollBus := pollbus.New(bus)
246+ go postOffice(bus, postWatch)
247+ go monitorAccounts(postWatch, pollBus)
248+
249+ if err := pollBus.Init(); err != nil {
250+ log.Fatal("Issue while setting up the poll bus:", err)
251+ }
252
253 done := make(chan bool)
254 <-done
255 }
256
257-func monitorAccounts(postWatch chan *PostWatch) {
258+func monitorAccounts(postWatch chan *PostWatch, pollBus *pollbus.PollBus) {
259 watcher := accounts.NewWatcher(SERVICETYPE_POLL)
260 mgr := make(map[uint]*AccountManager)
261+
262 L:
263- for data := range watcher.C {
264- if account, ok := mgr[data.AccountId]; ok {
265- if data.Enabled {
266- log.Println("New account data for existing account with id", data.AccountId)
267- account.updateAuthData(data)
268- } else {
269- account.Delete()
270- delete(mgr, data.AccountId)
271- }
272- } else if data.Enabled {
273- var plugin plugins.Plugin
274- switch data.ServiceName {
275- case SERVICENAME_GMAIL:
276- log.Println("Creating account with id", data.AccountId, "for", data.ServiceName)
277- plugin = gmail.New(data.AccountId)
278- case SERVICENAME_FACEBOOK:
279- // This is just stubbed until the plugin exists.
280- log.Println("Creating account with id", data.AccountId, "for", data.ServiceName)
281- plugin = facebook.New(data.AccountId)
282- case SERVICENAME_TWITTER:
283- // This is just stubbed until the plugin exists.
284- log.Println("Creating account with id", data.AccountId, "for", data.ServiceName)
285- plugin = twitter.New()
286- default:
287- log.Println("Unhandled account with id", data.AccountId, "for", data.ServiceName)
288- continue L
289- }
290- mgr[data.AccountId] = NewAccountManager(watcher, postWatch, plugin)
291- mgr[data.AccountId].updateAuthData(data)
292- go mgr[data.AccountId].Loop()
293+ for {
294+ select {
295+ case data := <-watcher.C:
296+ if account, ok := mgr[data.AccountId]; ok {
297+ if data.Enabled {
298+ log.Println("New account data for existing account with id", data.AccountId)
299+ account.updateAuthData(data)
300+ } else {
301+ account.Delete()
302+ delete(mgr, data.AccountId)
303+ }
304+ } else if data.Enabled {
305+ var plugin plugins.Plugin
306+ switch data.ServiceName {
307+ case SERVICENAME_GMAIL:
308+ log.Println("Creating account with id", data.AccountId, "for", data.ServiceName)
309+ plugin = gmail.New(data.AccountId)
310+ case SERVICENAME_FACEBOOK:
311+ // This is just stubbed until the plugin exists.
312+ log.Println("Creating account with id", data.AccountId, "for", data.ServiceName)
313+ plugin = facebook.New(data.AccountId)
314+ case SERVICENAME_TWITTER:
315+ // This is just stubbed until the plugin exists.
316+ log.Println("Creating account with id", data.AccountId, "for", data.ServiceName)
317+ plugin = twitter.New()
318+ default:
319+ log.Println("Unhandled account with id", data.AccountId, "for", data.ServiceName)
320+ continue L
321+ }
322+ mgr[data.AccountId] = NewAccountManager(watcher, postWatch, plugin)
323+ mgr[data.AccountId].updateAuthData(data)
324+ mgr[data.AccountId].Poll(true)
325+ }
326+ case <-pollBus.PollChan:
327+ var wg sync.WaitGroup
328+ for _, v := range mgr {
329+ wg.Add(1)
330+ poll := v.Poll
331+ go func() {
332+ defer wg.Done()
333+ poll(false)
334+ }()
335+ }
336+ wg.Wait()
337+ pollBus.SignalDone()
338 }
339 }
340 }
341
342=== added directory 'cmd/qtcontact-test'
343=== added file 'cmd/qtcontact-test/main.go'
344--- cmd/qtcontact-test/main.go 1970-01-01 00:00:00 +0000
345+++ cmd/qtcontact-test/main.go 2014-08-25 14:55:20 +0000
346@@ -0,0 +1,37 @@
347+/*
348+ Copyright 2014 Canonical Ltd.
349+ Authors: Sergio Schvezov <sergio.schvezov@canonical.com>
350+
351+ This program is free software: you can redistribute it and/or modify it
352+ under the terms of the GNU General Public License version 3, as published
353+ by the Free Software Foundation.
354+
355+ This program is distributed in the hope that it will be useful, but
356+ WITHOUT ANY WARRANTY; without even the implied warranties of
357+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
358+ PURPOSE. See the GNU General Public License for more details.
359+
360+ You should have received a copy of the GNU General Public License along
361+ with this program. If not, see <http://www.gnu.org/licenses/>.
362+*/
363+
364+package main
365+
366+import (
367+ "fmt"
368+ "os"
369+
370+ "launchpad.net/account-polld/qtcontact"
371+)
372+
373+func main() {
374+ qtcontact.MainLoopStart()
375+
376+ if len(os.Args) != 2 {
377+ fmt.Println("usage:", os.Args[0], "[email address]")
378+ os.Exit(1)
379+ }
380+
381+ path := qtcontact.GetAvatar(os.Args[1])
382+ fmt.Println("Avatar found:", path)
383+}
384
385=== modified file 'debian/control'
386--- debian/control 2014-07-31 18:08:37 +0000
387+++ debian/control 2014-08-25 14:55:20 +0000
388@@ -13,6 +13,9 @@
389 libaccounts-glib-dev,
390 libclick-0.4-dev,
391 libsignon-glib-dev,
392+ qt5-default,
393+ qtbase5-dev,
394+ qtpim5-dev,
395 Standards-Version: 3.9.5
396 Homepage: https://launchpad.net/account-polld
397 Vcs-Browser: http://bazaar.launchpad.net/~phablet-team/account-polld/trunk/files
398
399=== modified file 'debian/rules' (properties changed: +x to -x)
400=== modified file 'plugins/gmail/gmail.go'
401--- plugins/gmail/gmail.go 2014-08-08 20:11:14 +0000
402+++ plugins/gmail/gmail.go 2014-08-25 14:55:20 +0000
403@@ -32,6 +32,7 @@
404 "launchpad.net/account-polld/accounts"
405 "launchpad.net/account-polld/gettext"
406 "launchpad.net/account-polld/plugins"
407+ "launchpad.net/account-polld/qtcontact"
408 )
409
410 const (
411@@ -141,9 +142,12 @@
412 hdr := msg.Payload.mapHeaders()
413
414 from := hdr[hdrFROM]
415+ var avatarPath string
416+
417 if emailAddress, err := mail.ParseAddress(hdr[hdrFROM]); err == nil {
418 if emailAddress.Name != "" {
419 from = emailAddress.Name
420+ avatarPath = qtcontact.GetAvatar(emailAddress.Address)
421 }
422 }
423 msgStamp := hdr.getTimestamp()
424@@ -159,7 +163,7 @@
425 // fmt with label personal and threadId
426 action := fmt.Sprintf(gmailDispatchUrl, "personal", msg.ThreadId)
427 epoch := hdr.getEpoch()
428- pushMsgMap[msg.ThreadId] = *plugins.NewStandardPushMessage(summary, body, action, "", epoch)
429+ pushMsgMap[msg.ThreadId] = *plugins.NewStandardPushMessage(summary, body, action, avatarPath, epoch)
430 } else {
431 log.Print("gmail plugin ", p.accountId, ": skipping message id ", msg.Id, " with date ", msgStamp, " older than ", timeDelta)
432 }
433
434=== added directory 'pollbus'
435=== added file 'pollbus/bus.go'
436--- pollbus/bus.go 1970-01-01 00:00:00 +0000
437+++ pollbus/bus.go 2014-08-25 14:55:20 +0000
438@@ -0,0 +1,94 @@
439+/*
440+ Copyright 2014 Canonical Ltd.
441+ Authors: Sergio Schvezov <sergio.schvezov@canonical.com>
442+
443+ This program is free software: you can redistribute it and/or modify it
444+ under the terms of the GNU General Public License version 3, as published
445+ by the Free Software Foundation.
446+
447+ This program is distributed in the hope that it will be useful, but
448+ WITHOUT ANY WARRANTY; without even the implied warranties of
449+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
450+ PURPOSE. See the GNU General Public License for more details.
451+
452+ You should have received a copy of the GNU General Public License along
453+ with this program. If not, see <http://www.gnu.org/licenses/>.
454+*/
455+
456+package pollbus
457+
458+import (
459+ "fmt"
460+ "runtime"
461+
462+ "log"
463+
464+ "launchpad.net/go-dbus/v1"
465+)
466+
467+const (
468+ busInterface = "com.ubuntu.AccountPolld"
469+ busPath = "/com/ubuntu/AccountPolld"
470+ busName = "com.ubuntu.AccountPolld"
471+)
472+
473+type PollBus struct {
474+ conn *dbus.Connection
475+ msgChan chan *dbus.Message
476+ PollChan chan bool
477+}
478+
479+func New(conn *dbus.Connection) *PollBus {
480+ p := &PollBus{
481+ conn: conn,
482+ msgChan: make(chan *dbus.Message),
483+ PollChan: make(chan bool),
484+ }
485+ runtime.SetFinalizer(p, clean)
486+ return p
487+}
488+
489+func clean(p *PollBus) {
490+ p.conn.UnregisterObjectPath(busPath)
491+ close(p.msgChan)
492+ close(p.PollChan)
493+}
494+
495+func (p *PollBus) Init() error {
496+ name := p.conn.RequestName(busName, dbus.NameFlagDoNotQueue)
497+ err := <-name.C
498+ if err != nil {
499+ return fmt.Errorf("bus name could not be take: %s", err)
500+ }
501+
502+ go p.watchMethodCalls()
503+ p.conn.RegisterObjectPath(busPath, p.msgChan)
504+
505+ return nil
506+}
507+
508+func (p *PollBus) SignalDone() error {
509+ signal := dbus.NewSignalMessage(busPath, busInterface, "Done")
510+ if err := p.conn.Send(signal); err != nil {
511+ return err
512+ }
513+ return nil
514+}
515+
516+func (p *PollBus) watchMethodCalls() {
517+ for msg := range p.msgChan {
518+ var reply *dbus.Message
519+ switch {
520+ case msg.Interface == busInterface && msg.Member == "Poll":
521+ log.Println("Received Poll()")
522+ p.PollChan <- true
523+ reply = dbus.NewMethodReturnMessage(msg)
524+ default:
525+ log.Println("Received unkown method call on", msg.Interface, msg.Member)
526+ reply = dbus.NewErrorMessage(msg, "org.freedesktop.DBus.Error.UnknownMethod", "Unknown method")
527+ }
528+ if err := p.conn.Send(reply); err != nil {
529+ log.Println("Could not send reply:", err)
530+ }
531+ }
532+}
533
534=== added directory 'qtcontact'
535=== added file 'qtcontact/contacts.go'
536--- qtcontact/contacts.go 1970-01-01 00:00:00 +0000
537+++ qtcontact/contacts.go 2014-08-25 14:55:20 +0000
538@@ -0,0 +1,68 @@
539+/*
540+ Copyright 2014 Canonical Ltd.
541+ Authors: Sergio Schvezov <sergio.schvezov@canonical.com>
542+
543+ This program is free software: you can redistribute it and/or modify it
544+ under the terms of the GNU General Public License version 3, as published
545+ by the Free Software Foundation.
546+
547+ This program is distributed in the hope that it will be useful, but
548+ WITHOUT ANY WARRANTY; without even the implied warranties of
549+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
550+ PURPOSE. See the GNU General Public License for more details.
551+
552+ You should have received a copy of the GNU General Public License along
553+ with this program. If not, see <http://www.gnu.org/licenses/>.
554+*/
555+
556+package qtcontact
557+
558+// #cgo CXXFLAGS: -std=c++0x -pedantic-errors -Wall -fno-strict-aliasing -I/usr/share/c++/4.8
559+// #cgo LDFLAGS: -lstdc++
560+// #cgo pkg-config: Qt5Core Qt5Contacts
561+// #include "qtcontacts.h"
562+import "C"
563+
564+import (
565+ "log"
566+ "sync"
567+ "time"
568+)
569+
570+var (
571+ avatarPathChan chan string
572+ m sync.Mutex
573+)
574+
575+//export callback
576+func callback(path *C.char) {
577+ avatarPathChan <- C.GoString(path)
578+}
579+
580+func MainLoopStart() {
581+ go C.mainloopStart()
582+}
583+
584+// GetAvatar retrieves an avatar path for the specified email
585+// address. Multiple calls to this func will be in sync
586+func GetAvatar(emailAddress string) string {
587+ if emailAddress == "" {
588+ return ""
589+ }
590+
591+ m.Lock()
592+ defer m.Unlock()
593+
594+ avatarPathChan = make(chan string, 1)
595+ defer close(avatarPathChan)
596+
597+ C.getAvatar(C.CString(emailAddress))
598+
599+ select {
600+ case <-time.After(3 * time.Second):
601+ log.Println("Timeout while seeking avatar for", emailAddress)
602+ return ""
603+ case path := <-avatarPathChan:
604+ return path
605+ }
606+}
607
608=== added file 'qtcontact/qtcontacts.cpp'
609--- qtcontact/qtcontacts.cpp 1970-01-01 00:00:00 +0000
610+++ qtcontact/qtcontacts.cpp 2014-08-25 14:55:20 +0000
611@@ -0,0 +1,69 @@
612+/*
613+ Copyright 2014 Canonical Ltd.
614+ Authors: Sergio Schvezov <sergio.schvezov@canonical.com>
615+
616+ This program is free software: you can redistribute it and/or modify it
617+ under the terms of the GNU General Public License version 3, as published
618+ by the Free Software Foundation.
619+
620+ This program is distributed in the hope that it will be useful, but
621+ WITHOUT ANY WARRANTY; without even the implied warranties of
622+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
623+ PURPOSE. See the GNU General Public License for more details.
624+
625+ You should have received a copy of the GNU General Public License along
626+ with this program. If not, see <http://www.gnu.org/licenses/>.
627+*/
628+
629+#include <QContactManager>
630+#include <QContactFilter>
631+#include <QContactEmailAddress>
632+#include <QContactDetailFilter>
633+#include <QContactManager>
634+#include <QContactAvatar>
635+#include <QCoreApplication>
636+#include <QScopedPointer>
637+#include <QTimer>
638+#include <thread>
639+
640+#include "qtcontacts.h"
641+#include "qtcontacts.hpp"
642+#include "qtcontacts.moc"
643+
644+#ifdef __cplusplus
645+extern "C" {
646+#include "_cgo_export.h"
647+}
648+#endif
649+
650+QTCONTACTS_USE_NAMESPACE
651+
652+int mainloopStart() {
653+ static char empty[1] = {0};
654+ static char *argv[] = {empty, empty, empty};
655+ static int argc = 1;
656+
657+ QCoreApplication mApp(argc, argv);
658+ return mApp.exec();
659+}
660+
661+void getAvatar(char *email) {
662+ QScopedPointer<Avatar> avatar(new Avatar());
663+ avatar->retrieveThumbnail(QString(email));
664+}
665+
666+void Avatar::retrieveThumbnail(const QString& email) {
667+ QString avatar;
668+
669+ QContactManager manager ("galera");
670+ QContactDetailFilter filter(QContactEmailAddress::match(email));
671+ QList<QContact> contacts = manager.contacts(filter);
672+ if(contacts.size() > 0) {
673+ avatar = contacts[0].detail<QContactAvatar>().imageUrl().path();
674+ }
675+
676+ QByteArray byteArray = avatar.toUtf8();
677+ char* cString = byteArray.data();
678+
679+ callback(cString);
680+}
681
682=== added file 'qtcontact/qtcontacts.h'
683--- qtcontact/qtcontacts.h 1970-01-01 00:00:00 +0000
684+++ qtcontact/qtcontacts.h 2014-08-25 14:55:20 +0000
685@@ -0,0 +1,32 @@
686+/*
687+ Copyright 2014 Canonical Ltd.
688+ Authors: Sergio Schvezov <sergio.schvezov@canonical.com>
689+
690+ This program is free software: you can redistribute it and/or modify it
691+ under the terms of the GNU General Public License version 3, as published
692+ by the Free Software Foundation.
693+
694+ This program is distributed in the hope that it will be useful, but
695+ WITHOUT ANY WARRANTY; without even the implied warranties of
696+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
697+ PURPOSE. See the GNU General Public License for more details.
698+
699+ You should have received a copy of the GNU General Public License along
700+ with this program. If not, see <http://www.gnu.org/licenses/>.
701+*/
702+
703+#ifndef __QTCONTACTS_GOLANG__
704+#define __QTCONTACTS_GOLANG__
705+
706+#ifdef __cplusplus
707+extern "C" {
708+#endif
709+
710+void getAvatar(char *);
711+int mainloopStart();
712+
713+#ifdef __cplusplus
714+}
715+#endif
716+
717+#endif
718
719=== added file 'qtcontact/qtcontacts.hpp'
720--- qtcontact/qtcontacts.hpp 1970-01-01 00:00:00 +0000
721+++ qtcontact/qtcontacts.hpp 2014-08-25 14:55:20 +0000
722@@ -0,0 +1,33 @@
723+/*
724+ Copyright 2014 Canonical Ltd.
725+ Authors: Sergio Schvezov <sergio.schvezov@canonical.com>
726+
727+ This program is free software: you can redistribute it and/or modify it
728+ under the terms of the GNU General Public License version 3, as published
729+ by the Free Software Foundation.
730+
731+ This program is distributed in the hope that it will be useful, but
732+ WITHOUT ANY WARRANTY; without even the implied warranties of
733+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
734+ PURPOSE. See the GNU General Public License for more details.
735+
736+ You should have received a copy of the GNU General Public License along
737+ with this program. If not, see <http://www.gnu.org/licenses/>.
738+*/
739+
740+#ifndef __QTCONTACTS_HPP_
741+#define __QTCONTACTS_HPP_
742+
743+#include <QObject>
744+#include <QSignalMapper>
745+
746+class Avatar : QObject {
747+ Q_OBJECT
748+ public:
749+ explicit Avatar(QObject* parent=0)
750+ : QObject(parent) {
751+ }
752+ void retrieveThumbnail(const QString& email);
753+};
754+
755+#endif
756
757=== added file 'qtcontact/qtcontacts.moc'
758--- qtcontact/qtcontacts.moc 1970-01-01 00:00:00 +0000
759+++ qtcontact/qtcontacts.moc 2014-08-25 14:55:20 +0000
760@@ -0,0 +1,88 @@
761+/****************************************************************************
762+** Meta object code from reading C++ file 'qtcontacts.hpp'
763+**
764+** Created by: The Qt Meta Object Compiler version 67 (Qt 5.2.1)
765+**
766+** WARNING! All changes made in this file will be lost!
767+*****************************************************************************/
768+
769+#include "qtcontacts.hpp"
770+#include <QtCore/qbytearray.h>
771+#include <QtCore/qmetatype.h>
772+#if !defined(Q_MOC_OUTPUT_REVISION)
773+#error "The header file 'qtcontacts.hpp' doesn't include <QObject>."
774+#elif Q_MOC_OUTPUT_REVISION != 67
775+#error "This file was generated using the moc from 5.2.1. It"
776+#error "cannot be used with the include files from this version of Qt."
777+#error "(The moc has changed too much.)"
778+#endif
779+
780+QT_BEGIN_MOC_NAMESPACE
781+struct qt_meta_stringdata_Avatar_t {
782+ QByteArrayData data[1];
783+ char stringdata[8];
784+};
785+#define QT_MOC_LITERAL(idx, ofs, len) \
786+ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
787+ offsetof(qt_meta_stringdata_Avatar_t, stringdata) + ofs \
788+ - idx * sizeof(QByteArrayData) \
789+ )
790+static const qt_meta_stringdata_Avatar_t qt_meta_stringdata_Avatar = {
791+ {
792+QT_MOC_LITERAL(0, 0, 6)
793+ },
794+ "Avatar\0"
795+};
796+#undef QT_MOC_LITERAL
797+
798+static const uint qt_meta_data_Avatar[] = {
799+
800+ // content:
801+ 7, // revision
802+ 0, // classname
803+ 0, 0, // classinfo
804+ 0, 0, // methods
805+ 0, 0, // properties
806+ 0, 0, // enums/sets
807+ 0, 0, // constructors
808+ 0, // flags
809+ 0, // signalCount
810+
811+ 0 // eod
812+};
813+
814+void Avatar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
815+{
816+ Q_UNUSED(_o);
817+ Q_UNUSED(_id);
818+ Q_UNUSED(_c);
819+ Q_UNUSED(_a);
820+}
821+
822+const QMetaObject Avatar::staticMetaObject = {
823+ { &QObject::staticMetaObject, qt_meta_stringdata_Avatar.data,
824+ qt_meta_data_Avatar, qt_static_metacall, 0, 0}
825+};
826+
827+
828+const QMetaObject *Avatar::metaObject() const
829+{
830+ return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
831+}
832+
833+void *Avatar::qt_metacast(const char *_clname)
834+{
835+ if (!_clname) return 0;
836+ if (!strcmp(_clname, qt_meta_stringdata_Avatar.stringdata))
837+ return static_cast<void*>(const_cast< Avatar*>(this));
838+ return QObject::qt_metacast(_clname);
839+}
840+
841+int Avatar::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
842+{
843+ _id = QObject::qt_metacall(_c, _id, _a);
844+ if (_id < 0)
845+ return _id;
846+ return _id;
847+}
848+QT_END_MOC_NAMESPACE
849
850=== modified file 'update_translations.sh' (properties changed: +x to -x)

Subscribers

People subscribed via source and target branches