Merge remote-tracking branch 'cr.ssh/develop'

This commit is contained in:
Xu Fasheng 2015-06-16 17:20:55 +08:00
commit be157d8768
233 changed files with 10204 additions and 7436 deletions

2
.gitignore vendored
View File

@ -5,8 +5,6 @@ test-*
test_*
_*
*.*~
*.cfg
*.ini
.#*
.test
*/*.test

View File

@ -48,6 +48,9 @@ out/locale/%/LC_MESSAGES/dde-daemon.mo:misc/po/%.po
translate: $(addsuffix /LC_MESSAGES/dde-daemon.mo, $(addprefix out/locale/, ${LANGUAGES}))
pot:
deepin-update-pot misc/po/locale_config.ini
build: prepare $(addprefix out/bin/, ${BINARIES})
test: prepare
@ -71,14 +74,13 @@ install: build translate
cp misc/polkit-action/* ${DESTDIR}${PREFIX}/share/polkit-1/actions/
mkdir -pv ${DESTDIR}${PREFIX}/share/glib-2.0/schemas
cp misc/schemas/* ${DESTDIR}${PREFIX}/share/glib-2.0/schemas
cp misc/schemas/*.xml ${DESTDIR}${PREFIX}/share/glib-2.0/schemas/
cp misc/schemas/wrap/*.xml ${DESTDIR}${PREFIX}/share/glib-2.0/schemas/
cp misc/schemas/wrap/*.convert ${DESTDIR}${PREFIX}/share/glib-2.0/schemas/
mkdir -pv ${DESTDIR}${PREFIX}/share/dde-daemon
cp -r misc/usr/share/dde-daemon/* ${DESTDIR}${PREFIX}/share/dde-daemon/
mkdir -pv ${DESTDIR}${PREFIX}/bin
cp misc/tool/wireless_script*.sh ${DESTDIR}${PREFIX}/bin/wireless-script
mkdir -pv ${DESTDIR}${PREFIX}/share/personalization/thumbnail
cp -r misc/thumbnail/* ${DESTDIR}${PREFIX}/share/personalization/thumbnail/

View File

@ -1,236 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
import (
"fmt"
. "pkg.linuxdeepin.com/dde-daemon/accounts/username_checker"
"pkg.linuxdeepin.com/lib/dbus"
dutils "pkg.linuxdeepin.com/lib/utils"
"strings"
)
const newUserConfigFile = "/etc/adduser.conf"
func (obj *Manager) CreateGuestAccount() string {
args := []string{}
shell, err := getNewUserDefaultShell(newUserConfigFile)
if err != nil {
logger.Debug(err)
}
username := getGuestName()
passwd := encodePasswd("")
args = append(args, "-m")
if len(shell) != 0 {
args = append(args, "-s")
args = append(args, shell)
}
args = append(args, "-d")
args = append(args, "/tmp/"+username)
args = append(args, "-l")
args = append(args, "-p")
args = append(args, passwd)
args = append(args, username)
if !execCommand(CMD_USERADD, args) {
return ""
}
info, _ := getUserInfoByName(username)
return info.Path
}
func (obj *Manager) AllowGuestAccount(dbusMsg dbus.DMessage, allow bool) bool {
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if ok := dutils.WriteKeyToKeyFile(ACCOUNT_CONFIG_FILE,
ACCOUNT_GROUP_KEY, ACCOUNT_KEY_GUEST, allow); !ok {
logger.Error("AllowGuest Failed")
return false
}
return true
}
func (obj *Manager) CreateUser(dbusMsg dbus.DMessage, name, fullname string, accountTyte int32) error {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In CreateUser:%v",
err)
}
}()
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return fmt.Errorf("Authentication failed")
}
go func() {
args := []string{}
shell, err := getNewUserDefaultShell(newUserConfigFile)
if err != nil {
logger.Debug(err)
}
args = append(args, "-m")
if len(shell) != 0 {
args = append(args, "-s")
args = append(args, shell)
}
args = append(args, "-c")
args = append(args, fullname)
args = append(args, name)
if !execCommand(CMD_USERADD, args) {
return
}
info, _ := getUserInfoByName(name)
u, ok := obj.pathUserMap[info.Path]
if ok {
u.setAccountType(accountTyte)
}
changeFileOwner(name, name, "/home/"+name)
}()
return nil
}
func (obj *Manager) DeleteUser(dbusMsg dbus.DMessage, name string, removeFiles bool) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In DeleteUser:%v",
err)
}
}()
//if ok := opUtils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
args := []string{}
user, ok := obj.pathUserMap[obj.FindUserByName(name)]
if ok {
if user.AutomaticLogin {
user.SetAutomaticLogin(dbusMsg, false)
}
}
if removeFiles {
args = append(args, "-r")
}
args = append(args, "-f")
args = append(args, name)
if !execCommand("/bin/rm", []string{"-rf", "/etc/subuid"}) {
return false
}
if !execCommand(CMD_USERDEL, args) {
return false
}
if removeFiles {
obj.rmAllIconFileByName(name)
}
return true
}
func (obj *Manager) FindUserById(id string) string {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In FindUserById:%v",
err)
}
}()
path := USER_MANAGER_PATH + id
for _, v := range obj.UserList {
if path == v {
return path
}
}
return ""
}
func (obj *Manager) FindUserByName(name string) string {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In FindUserByName:%v", err)
}
}()
if info, ok := getUserInfoByName(name); ok {
return info.Path
}
return ""
}
func (obj *Manager) RandUserIcon() (string, bool) {
if icon := getRandUserIcon(); len(icon) > 0 {
return icon, true
}
return "", false
}
func (m *Manager) IsUsernameValid(username string) (bool, string, int32) {
err := CheckUsernameValid(username)
if err != nil {
return false, err.Message.Error(), err.Code
}
return true, "", -1
}
func (m *Manager) IsPasswordValid(passwd string) bool {
return true
}
func (m *Manager) rmAllIconFileByName(username string) {
if len(username) < 1 {
return
}
list := []string{}
localList := getIconList(ICON_LOCAL_DIR)
for _, l := range localList {
if strings.Contains(l, username+"-") {
list = append(list, l)
}
}
for _, v := range list {
rmAllFile(v)
}
}

View File

@ -1,144 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
import (
"fmt"
"pkg.linuxdeepin.com/lib/dbus"
)
func (obj *Manager) GetDBusInfo() dbus.DBusInfo {
return dbus.DBusInfo{
Dest: ACCOUNT_DEST,
ObjectPath: ACCOUNT_MANAGER_PATH,
Interface: ACCOUNT_MANAGER_IFC,
}
}
func (obj *Manager) setPropUserList(list []string) {
if !isStrListEqual(obj.UserList, list) {
obj.UserList = list
dbus.NotifyChange(obj, "UserList")
}
}
func (obj *Manager) setPropAllowGuest(isAllow bool) {
if obj.AllowGuest != isAllow {
obj.AllowGuest = isAllow
dbus.NotifyChange(obj, "AllowGuest")
}
}
func (m *Manager) setPropGuestIcon(icon string) {
if m.GuestIcon != icon {
m.GuestIcon = icon
dbus.NotifyChange(m, "GuestIcon")
}
}
func (obj *Manager) newUserByPath(path string) error {
if len(path) == 0 {
return fmt.Errorf("Invalid ObjectPath")
}
u := newUser(path)
if u == nil {
return fmt.Errorf("Create User Object Failed")
}
if err := dbus.InstallOnSystem(u); err != nil {
return fmt.Errorf("Install DBus For %s Failed: %v", path, err)
}
u.setProps()
obj.pathUserMap[path] = u
return nil
}
func (m *Manager) destroyUser(path string) {
u, ok := m.pathUserMap[path]
if !ok {
return
}
if u.watcher != nil {
u.quitFlag <- true
u.watcher.Close()
}
dbus.UnInstallObject(u)
u = nil
delete(m.pathUserMap, path)
}
func (m *Manager) destroyAllUser() {
for _, path := range m.UserList {
m.destroyUser(path)
}
m.pathUserMap = make(map[string]*User)
}
func (obj *Manager) updateAllUserInfo() {
obj.destroyAllUser()
for _, path := range obj.UserList {
err := obj.newUserByPath(path)
if err != nil {
logger.Error(err)
}
}
}
func (m *Manager) handleuserAdded(list []string) {
for _, path := range list {
err := m.newUserByPath(path)
if err != nil {
logger.Error(err)
continue
}
dbus.Emit(m, "UserAdded", path)
}
m.setPropUserList(getUserList())
}
func (m *Manager) handleUserRemoved(list []string) {
for _, path := range list {
m.destroyUser(path)
dbus.Emit(m, "UserDeleted", path)
}
m.setPropUserList(getUserList())
}
func (obj *Manager) destroy() {
if obj.listWatcher != nil {
obj.listQuit <- true
obj.listWatcher.Close()
}
if obj.infoWatcher != nil {
obj.infoQuit <- true
obj.infoWatcher.Close()
}
obj.destroyAllUser()
}

View File

@ -22,242 +22,48 @@
package accounts
import (
"bufio"
"github.com/howeyc/fsnotify"
"io/ioutil"
"os"
dutils "pkg.linuxdeepin.com/lib/utils"
"regexp"
"strconv"
"strings"
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/log"
)
type Manager struct {
UserList []string
AllowGuest bool
GuestIcon string
pathUserMap map[string]*User
var (
_m *Manager
logger = log.NewLogger(dbusSender)
)
listWatcher *fsnotify.Watcher
infoWatcher *fsnotify.Watcher
listQuit chan bool
infoQuit chan bool
UserAdded func(string)
UserDeleted func(string)
Error func(string)
}
var _manager *Manager
func GetManager() *Manager {
if _manager == nil {
_manager = newManager()
func Start() {
if _m != nil {
return
}
return _manager
}
func newManager() *Manager {
obj := &Manager{}
obj.pathUserMap = make(map[string]*User)
obj.setPropUserList(getUserList())
obj.setPropAllowGuest(isAllowGuest())
obj.setPropGuestIcon(GUEST_USER_ICON)
var err error
obj.listWatcher, err = fsnotify.NewWatcher()
logger.BeginTracing()
_m = NewManager()
err := dbus.InstallOnSystem(_m)
if err != nil {
logger.Error("New User List Watcher Failed:", err)
}
obj.infoWatcher, err = fsnotify.NewWatcher()
if err != nil {
logger.Error("New User Info Watcher Failed:", err)
logger.Error("Install manager dbus failed:", err)
if _m.watcher != nil {
_m.watcher.EndWatch()
_m.watcher = nil
}
return
}
if obj.listWatcher != nil {
obj.listQuit = make(chan bool)
obj.watchUserListFile()
go obj.handleUserListChanged()
}
if obj.infoWatcher != nil {
obj.infoQuit = make(chan bool)
obj.watchUserInfoFile()
go obj.handleUserInfoChanged()
}
return obj
_m.installUsers()
}
func getUserInfoList() []UserInfo {
contents, err := ioutil.ReadFile(ETC_PASSWD)
if err != nil {
logger.Errorf("ReadFile '%s' failed: %s", ETC_PASSWD, err)
return nil
func Stop() {
if _m == nil {
return
}
infos := []UserInfo{}
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
strs := strings.Split(line, ":")
/* len of each line in /etc/passwd by spliting ':' is 7 */
if len(strs) != PASSWD_SPLIT_LEN {
continue
}
info := newUserInfo(strs[0], strs[2], strs[3],
strs[5], strs[6])
if checkUserIsHuman(&info) {
infos = append(infos, info)
}
}
return infos
_m.destroy()
_m = nil
}
func newUserInfo(name, uid, gid, home, shell string) UserInfo {
info := UserInfo{}
func triggerSigErr(pid uint32, action, reason string) {
if _m == nil {
return
}
info.Name = name
info.Uid = uid
info.Gid = gid
info.Home = home
info.Shell = shell
info.Path = USER_MANAGER_PATH + uid
return info
}
func checkUserIsHuman(info *UserInfo) bool {
if info.Name == "root" {
return false
}
shells := strings.Split(info.Shell, "/")
tmpShell := shells[len(shells)-1]
if SHELL_END_FALSE == tmpShell ||
SHELL_END_NOLOGIN == tmpShell {
return false
}
if !detectedViaShadowFile(info) {
id, _ := strconv.ParseInt(info.Uid, 10, 64)
if id < 1000 {
return false
}
}
return true
}
func detectedViaShadowFile(info *UserInfo) bool {
contents, err := ioutil.ReadFile(ETC_SHADOW)
if err != nil {
logger.Errorf("ReadFile '%s' failed: %s", ETC_SHADOW, err)
return false
}
isHuman := false
info.Locked = false
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
strs := strings.Split(line, ":")
if len(strs) != SHADOW_SPLIT_LEN {
continue
}
if strs[0] != info.Name {
continue
}
pw := strs[1]
if pw[0] == '*' {
break
}
if pw[0] == '!' {
info.Locked = true
}
//加盐密码最短为13
if len(pw) < 13 {
break
}
isHuman = true
}
return isHuman
}
func getUserList() []string {
infos := getUserInfoList()
list := []string{}
for _, info := range infos {
list = append(list, info.Path)
}
return list
}
func isAllowGuest() bool {
if v, ok := dutils.ReadKeyFromKeyFile(ACCOUNT_CONFIG_FILE,
ACCOUNT_GROUP_KEY, ACCOUNT_KEY_GUEST, true); !ok {
dutils.WriteKeyToKeyFile(ACCOUNT_CONFIG_FILE,
ACCOUNT_GROUP_KEY, ACCOUNT_KEY_GUEST, false)
return false
} else {
if ret, ok := v.(bool); ok {
return ret
}
}
return false
}
func getUserInfoByPath(path string) (UserInfo, bool) {
for _, info := range getUserInfoList() {
if path == info.Path {
return info, true
}
}
return UserInfo{}, false
}
func getUserInfoByName(name string) (UserInfo, bool) {
for _, info := range getUserInfoList() {
if name == info.Name {
return info, true
}
}
return UserInfo{}, false
}
func getNewUserDefaultShell(filename string) (string, error) {
fp, err := os.Open(filename)
if err != nil {
return "", err
}
var shell string
match := regexp.MustCompile(`^DSHELL=(.*)`)
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := scanner.Text()
fields := match.FindStringSubmatch(line)
if len(fields) > 1 {
shell = fields[1]
break
}
}
fp.Close()
return shell, nil
dbus.Emit(_m, "Error", pid, action, reason)
}

View File

@ -0,0 +1,92 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package checkers
import (
C "launchpad.net/gocheck"
"testing"
)
type testWrapper struct{}
func init() {
C.Suite(&testWrapper{})
}
func Test(t *testing.T) {
C.TestingT(t)
}
func (*testWrapper) TestCheckUsername(c *C.C) {
type checkRet struct {
name string
code ErrorCode
}
var infos = []checkRet{
{"", ErrCodeEmpty},
{"a1111111111111111111111111111111", 0},
{"a11111111111111111111111111111111", ErrCodeLenMoreThen},
{"root", ErrCodeSystemUsed},
{"123", ErrCodeFirstNotLower},
{"a123*&", ErrCodeInvalidChar},
}
for _, v := range infos {
tmp := CheckUsernameValid(v.name)
if v.code == 0 {
c.Check(tmp, C.Equals, (*ErrorInfo)(nil))
} else {
c.Check(tmp.Code, C.Equals, v.code)
}
}
}
func (*testWrapper) TestGetUsernames(c *C.C) {
var datas = []struct {
name string
ret bool
}{
{
name: "test1",
ret: true,
},
{
name: "test2",
ret: true,
},
{
name: "test3",
ret: false,
},
}
names, err := getAllUsername("testdata/passwd")
c.Check(err, C.Equals, nil)
c.Check(len(names), C.Equals, 2)
for _, data := range datas {
c.Check(isStrInArray(data.name, names), C.Equals, data.ret)
c.Check(isStrInArray(data.name, names), C.Equals, data.ret)
c.Check(isStrInArray(data.name, names), C.Equals, data.ret)
}
}

View File

@ -19,14 +19,14 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package datetime
package checkers
import (
"pkg.linuxdeepin.com/lib/gio-2.0"
)
func isStrInArray(str string, array []string) bool {
for _, v := range array {
if v == str {
return true
}
}
func (date *DateTime) listenGSettings() {
date.settings.Connect("changed::is-auto-set", func(s *gio.Settings, key string) {
date.enableNTP(date.settings.GetBoolean(key))
})
return false
}

2
accounts/checkers/testdata/passwd vendored Normal file
View File

@ -0,0 +1,2 @@
test1:x:1001:1001::/home/test1:/bin/bash
test2:x:1002:1002::/home/test2:/bin/bash

View File

@ -0,0 +1,182 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package checkers
import (
"fmt"
"io/ioutil"
"os/user"
. "pkg.linuxdeepin.com/lib/gettext"
"regexp"
"strconv"
"strings"
)
const (
userNameMaxLength = 32
passwdFile = "/etc/passwd"
groupFile = "/etc/group"
)
type ErrorCode int32
type ErrorInfo struct {
Code ErrorCode
Error error
}
const (
ErrCodeEmpty ErrorCode = iota + 1
ErrCodeInvalidChar
ErrCodeFirstNotLower
ErrCodeExist
ErrCodeSystemUsed
ErrCodeLenMoreThen
)
func (code ErrorCode) Error() *ErrorInfo {
var err error
switch code {
case ErrCodeEmpty:
err = fmt.Errorf(Tr("Username can not be empty."))
case ErrCodeInvalidChar:
err = fmt.Errorf(Tr("Username must comprise a~z, 0~9, - or _."))
case ErrCodeFirstNotLower:
err = fmt.Errorf(Tr("The first character must be in lower case."))
case ErrCodeExist:
err = fmt.Errorf(Tr("The username exists."))
case ErrCodeSystemUsed:
err = fmt.Errorf(Tr("The username has been used by system."))
case ErrCodeLenMoreThen:
err = fmt.Errorf(Tr("The username' length exceeds the limit"))
default:
return nil
}
return &ErrorInfo{
Code: code,
Error: err,
}
}
func CheckUsernameValid(name string) *ErrorInfo {
if len(name) == 0 {
return ErrCodeEmpty.Error()
}
if len(name) > userNameMaxLength {
return ErrCodeLenMoreThen.Error()
}
if Username(name).isNameExist() {
id, err := Username(name).getUid()
if err != nil || id >= 1000 {
return ErrCodeExist.Error()
} else {
return ErrCodeSystemUsed.Error()
}
}
if !Username(name).isLowerCharStart() {
return ErrCodeFirstNotLower.Error()
}
if !Username(name).isStringValid() {
return ErrCodeInvalidChar.Error()
}
return nil
}
type Username string
type UsernameList []string
func (name Username) isNameExist() bool {
names, err := getAllUsername(passwdFile)
if err != nil {
return false
}
if !isStrInArray(string(name), names) {
return false
}
return true
}
func (name Username) isLowerCharStart() bool {
match := regexp.MustCompile(`^[a-z]`)
if !match.MatchString(string(name)) {
return false
}
return true
}
func (name Username) isStringValid() bool {
match := regexp.MustCompile(`^[a-z][a-z0-9_-]*$`)
if !match.MatchString(string(name)) {
return false
}
return true
}
func (name Username) getUid() (int64, error) {
u, err := user.Lookup(string(name))
if err != nil {
return -1, err
}
id, err := strconv.ParseInt(u.Uid, 10, 64)
if err != nil {
return -1, err
}
return id, nil
}
func getAllUsername(file string) (UsernameList, error) {
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
var names UsernameList
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if len(line) == 0 {
continue
}
items := strings.Split(line, ":")
if len(items) < 3 {
continue
}
names = append(names, items[0])
}
return names, nil
}

View File

@ -1,297 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
// #cgo CFLAGS: -Wall -g
// #cgo LDFLAGS: -lcrypt
// #include <stdlib.h>
// #include "mkpasswd.h"
import "C"
import (
libpolkit1 "dbus/org/freedesktop/policykit1"
"errors"
"io/ioutil"
"math/rand"
"os"
"os/exec"
"pkg.linuxdeepin.com/lib/dbus"
dutils "pkg.linuxdeepin.com/lib/utils"
"strings"
"sync"
"time"
"unsafe"
)
const (
POLKIT_DEST = "org.freedesktop.PolicyKit1"
POLKIT_PATH = "/org/freedesktop/PolicyKit1/Authority"
POLKIT_IFC = "org.freedesktop.PolicyKit1.Authority"
)
func getGuestName() string {
seedStr := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
l := len(seedStr)
name := "guest-"
for i := 0; i < 6; i++ {
rand.Seed(time.Now().Unix() * int64((i+2)*(i+3)))
index := rand.Intn(l)
name += string(seedStr[index])
}
return name
}
func execCommand(cmd string, args []string) bool {
if out, err := exec.Command(cmd, args...).CombinedOutput(); err != nil {
dbus.Emit(GetManager(), "Error", string(out))
logger.Warningf("Exec '%s %v' failed: %v", cmd, args, err)
return false
}
return true
}
func strIsInList(str string, list []string) bool {
for _, v := range list {
if str == v {
return true
}
}
return false
}
func isStrListEqual(list1, list2 []string) bool {
l1 := len(list1)
l2 := len(list2)
if l1 != l2 {
return false
}
for i := 0; i < l1; i++ {
if list1[i] != list2[i] {
return false
}
}
return true
}
func deleteStrFromList(ele string, list []string) []string {
tmp := []string{}
for _, l := range list {
if ele == l {
continue
}
tmp = append(tmp, l)
}
return tmp
}
func compareStrList(list1, list2 []string) ([]string, int) {
if isStrListEqual(list1, list2) {
return nil, 0
}
l1 := len(list1)
l2 := len(list2)
tmp := []string{}
if l1 < l2 {
for i := 0; i < l2; i++ {
j := 0
for ; j < l1; j++ {
if list1[j] == list2[i] {
break
}
}
if j == l1 {
tmp = append(tmp, list2[i])
}
}
return tmp, 1
}
if l1 > l2 {
for i := 0; i < l1; i++ {
j := 0
for ; j < l2; j++ {
if list1[i] == list2[j] {
break
}
}
if j == l2 {
tmp = append(tmp, list1[i])
}
}
return tmp, -1
}
return tmp, 0
}
func changeFileOwner(user, group, dir string) {
args := []string{}
args = append(args, "-R")
args = append(args, user+":"+group)
args = append(args, dir)
go execCommand(CMD_CHOWN, args)
}
func encodePasswd(words string) string {
str := C.CString(words)
defer C.free(unsafe.Pointer(str))
ret := C.mkpasswd(str)
return C.GoString(ret)
}
func changePasswd(username, password string) {
data, err := ioutil.ReadFile(ETC_SHADOW)
if err != nil {
return
}
lines := strings.Split(string(data), "\n")
index := 0
line := ""
okFlag := false
for index, line = range lines {
strs := strings.Split(line, ":")
if strs[0] == username {
if strs[1] == password {
break
}
strs[1] = password
l := len(strs)
line = ""
for i, s := range strs {
if i == l-1 {
line += s
continue
}
line += s + ":"
}
okFlag = true
break
}
}
if okFlag {
okFlag = false
contents := ""
l := len(lines)
for i, tmp := range lines {
if i == index {
contents += line
} else {
contents += tmp
}
if i < l-1 {
contents += "\n"
}
}
f, err := os.Create(ETC_SHADOW_BAK)
if err != nil {
logger.Errorf("Create '%s' failed: %v\n",
ETC_SHADOW_BAK, err)
panic(err)
}
defer f.Close()
var mutex sync.Mutex
mutex.Lock()
_, err = f.WriteString(contents)
if err != nil {
logger.Errorf("WriteString '%s' failed: %v\n",
ETC_SHADOW_BAK, err)
panic(err)
}
f.Sync()
os.Rename(ETC_SHADOW_BAK, ETC_SHADOW)
os.Chmod(ETC_SHADOW, 0600)
mutex.Unlock()
}
}
type polkitSubject struct {
/*
* The following kinds of subjects are known:
* Unix Process: should be set to unix-process with keys
* pid (of type uint32) and
* start-time (of type uint64)
* Unix Session: should be set to unix-session with the key
* session-id (of type string)
* System Bus Name: should be set to system-bus-name with the key
* name (of type string)
*/
SubjectKind string
SubjectDetails map[string]dbus.Variant
}
func polkitAuthWithPid(actionId string, pid uint32) bool {
objPolkit, err := libpolkit1.NewAuthority("org.freedesktop.PolicyKit1",
"/org/freedesktop/PolicyKit1/Authority")
if err != nil {
logger.Error("New PolicyKit Object Failed: ", err)
return false
}
subject := polkitSubject{}
subject.SubjectKind = "unix-process"
subject.SubjectDetails = make(map[string]dbus.Variant)
subject.SubjectDetails["pid"] = dbus.MakeVariant(uint32(pid))
subject.SubjectDetails["start-time"] = dbus.MakeVariant(uint64(0))
details := make(map[string]string)
details[""] = ""
flags := uint32(1)
cancelId := ""
ret, err1 := objPolkit.CheckAuthorization(subject, actionId, details,
flags, cancelId)
if err1 != nil {
logger.Error("CheckAuthorization Failed: ", err1)
return false
}
// Is Authority
if !ret[0].(bool) {
return false
}
return true
}
func rmAllFile(filename string) error {
if !dutils.IsFileExist(filename) {
return errors.New("File not exist")
}
return os.RemoveAll(filename)
}

View File

@ -1,102 +0,0 @@
/**
* Copyright (c) 2011 ~ 2013 Deepin, Inc.
* 2011 ~ 2013 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
type UserInfo struct {
Name string
Uid string
Gid string
Home string
Shell string
Path string
Locked bool
}
const (
ACCOUNT_DEST = "com.deepin.daemon.Accounts"
ACCOUNT_MANAGER_PATH = "/com/deepin/daemon/Accounts"
ACCOUNT_MANAGER_IFC = "com.deepin.daemon.Accounts"
USER_MANAGER_PATH = "/com/deepin/daemon/Accounts/User"
USER_MANAGER_IFC = "com.deepin.daemon.Accounts.User"
)
const (
ETC_PASSWD = "/etc/passwd"
ETC_SHADOW = "/etc/shadow"
ETC_SHADOW_BAK = "/etc/shadow.bak"
ETC_GROUP = "/etc/group"
ETC_DISPLAY_MANAGER = "/etc/X11/default-display-manager"
ETC_LIGHTDM_CONFIG = "/etc/lightdm/lightdm.conf"
ETC_GDM_CONFIG = "/etc/gdm/custom.conf"
ETC_KDM_CONFIG = "/etc/kde4/kdm/kdmrc"
USER_KDM_CONFIG = "/usr/share/config/kdm/kdmrc"
LIGHTDM_AUTOLOGIN_GROUP = "SeatDefaults"
LIGHTDM_AUTOLOGIN_USER = "autologin-user"
GDM_AUTOLOGIN_GROUP = "daemon"
GDM_AUTOLOGIN_USER = "AutomaticLogin"
KDM_AUTOLOGIN_GROUP = "X-:0-Core"
KDM_AUTOLOGIN_ENABLE = "AutoLoginEnable"
KDM_AUTOLOGIN_USER = "AutoLoginUser"
ETC_PERM = 0644
PASSWD_SPLIT_LEN = 7
SHADOW_SPLIT_LEN = 9
GROUP_SPLIT_LEN = 4
)
const (
SHELL_END_FALSE = "false"
SHELL_END_NOLOGIN = "nologin"
KEY_TYPE_BOOL = 0
KEY_TYPE_INT = 1
KEY_TYPE_STRING = 2
KEY_TYPE_STRING_LIST = 3
ACCOUNT_TYPE_STANDARD = 0
ACCOUNT_TYPE_ADMINISTRATOR = 1
GUEST_USER_ICON = "/var/lib/AccountsService/icons/guest.png"
ACCOUNT_CONFIG_FILE = "/var/lib/AccountsService/accounts.ini"
ACCOUNT_GROUP_KEY = "Accounts"
ACCOUNT_KEY_GUEST = "AllowGuest"
USER_ICON_DIR = "/var/lib/AccountsService/icons/"
USER_DEFAULT_ICON = USER_ICON_DIR + "1.png"
USER_CONFIG_DIR = "/var/lib/AccountsService/users"
ICON_SYSTEM_DIR = "/var/lib/AccountsService/icons"
ICON_LOCAL_DIR = "/var/lib/AccountsService/icons/local"
USER_DEFAULT_BG = "file:///usr/share/backgrounds/default_background.jpg"
)
const (
CMD_USERADD = "/usr/sbin/useradd"
CMD_USERDEL = "/usr/sbin/userdel"
CMD_CHOWN = "/bin/chown"
CMD_USERMOD = "/usr/sbin/usermod"
CMD_GPASSWD = "/usr/bin/gpasswd"
POLKIT_CHANGED_OWN_DATA = "com.deepin.daemon.accounts.change-own-user-data"
POLKIT_MANAGER_USER = "com.deepin.daemon.accounts.user-administration"
POLKIT_SET_LOGIN_OPTION = "com.deepin.daemon.accounts.set-login-option"
)

View File

@ -1,6 +1,6 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
@ -23,280 +23,144 @@ package accounts
import (
"github.com/howeyc/fsnotify"
"path"
dutils "pkg.linuxdeepin.com/lib/utils"
"regexp"
"sync"
"pkg.linuxdeepin.com/lib/dbus"
"strings"
"time"
)
var _handleFlag = false
const (
userFileGroup = "/etc/group"
userFileShadow = "/etc/shadow"
func (obj *Manager) watchUserListFile() {
var err error
permModeDir = 0755
)
if obj.listWatcher == nil {
if obj.listWatcher, err = fsnotify.NewWatcher(); err != nil {
logger.Error("New User List Watcher Failed:", err)
return
}
}
const (
userListNotChange int = iota + 1
userListAdded
userListDeleted
)
obj.listWatcher.Watch(ETC_SHADOW)
obj.listWatcher.Watch(ACCOUNT_CONFIG_FILE)
func (m *Manager) getWatchFiles() []string {
return []string{userFileGroup, userFileShadow}
}
func (obj *Manager) removeUserListFileWatch() {
if obj.listWatcher == nil {
func (m *Manager) handleFileChanged(ev *fsnotify.FileEvent) {
if ev == nil {
return
}
obj.listWatcher.RemoveWatch(ETC_SHADOW)
obj.listWatcher.RemoveWatch(ACCOUNT_CONFIG_FILE)
}
func (obj *Manager) watchUserInfoFile() {
var err error
if obj.infoWatcher == nil {
if obj.infoWatcher, err = fsnotify.NewWatcher(); err != nil {
logger.Error("New User Info Watcher Failed:", err)
return
}
}
obj.infoWatcher.Watch(ETC_GROUP)
obj.infoWatcher.Watch(ETC_SHADOW)
obj.infoWatcher.Watch(ICON_SYSTEM_DIR)
obj.infoWatcher.Watch(ICON_LOCAL_DIR)
if dutils.IsFileExist(ETC_LIGHTDM_CONFIG) {
obj.infoWatcher.Watch(ETC_LIGHTDM_CONFIG)
}
if dutils.IsFileExist(ETC_GDM_CONFIG) {
obj.infoWatcher.Watch(ETC_GDM_CONFIG)
}
if dutils.IsFileExist(ETC_KDM_CONFIG) {
obj.infoWatcher.Watch(ETC_KDM_CONFIG)
switch {
case strings.Contains(ev.Name, userFileGroup):
m.handleUserFileChanged(ev, m.handleFileGroupChanged)
case strings.Contains(ev.Name, userFileShadow):
m.handleUserFileChanged(ev, m.handleFileShadowChanged)
}
}
func (obj *Manager) removeUserInfoFileWatch() {
if obj.infoWatcher == nil {
func (m *Manager) handleUserFileChanged(ev *fsnotify.FileEvent, handler func()) {
if !ev.IsDelete() || handler == nil {
return
}
obj.infoWatcher.RemoveWatch(ETC_GROUP)
obj.infoWatcher.RemoveWatch(ETC_SHADOW)
obj.infoWatcher.RemoveWatch(ICON_SYSTEM_DIR)
obj.infoWatcher.RemoveWatch(ICON_LOCAL_DIR)
if dutils.IsFileExist(ETC_LIGHTDM_CONFIG) {
obj.infoWatcher.RemoveWatch(ETC_LIGHTDM_CONFIG)
}
if dutils.IsFileExist(ETC_GDM_CONFIG) {
obj.infoWatcher.RemoveWatch(ETC_GDM_CONFIG)
}
if dutils.IsFileExist(ETC_KDM_CONFIG) {
obj.infoWatcher.RemoveWatch(ETC_KDM_CONFIG)
m.watcher.ResetFileListWatch()
<-time.After(time.Millisecond * 200)
handler()
}
func (m *Manager) handleFileGroupChanged() {
m.mapLocker.Lock()
defer m.mapLocker.Unlock()
for _, u := range m.usersMap {
u.updatePropAccountType()
}
}
var uLock sync.Mutex
func (m *Manager) handleFileShadowChanged() {
m.refreshUserList()
func (obj *Manager) handleUserListChanged() {
for {
select {
case <-obj.listQuit:
return
case ev, ok := <-obj.listWatcher.Event:
if !ok {
if obj.listWatcher != nil {
obj.removeUserListFileWatch()
}
obj.watchUserListFile()
break
}
if ev == nil {
break
}
//Update the property 'Locked'
m.mapLocker.Lock()
defer m.mapLocker.Unlock()
for _, u := range m.usersMap {
u.updatePropLocked()
}
}
if ok, _ := regexp.MatchString(`\.swa?px?$`, ev.Name); ok {
break
}
func (m *Manager) refreshUserList() {
newList := getUserPaths()
ret, status := compareUserList(m.UserList, newList)
switch status {
case userListAdded:
m.handleUserAdded(ret)
case userListDeleted:
m.handleUserDeleted(ret)
}
}
logger.Debug("User List Event:", ev)
if ev.IsDelete() {
obj.removeUserListFileWatch()
obj.watchUserListFile()
//break
}
ok1, _ := regexp.MatchString(ACCOUNT_CONFIG_FILE, ev.Name)
if ok1 {
obj.setPropAllowGuest(isAllowGuest())
break
}
if !_handleFlag {
uLock.Lock()
_handleFlag = true
list, ret := compareStrList(obj.UserList, getUserList())
switch ret {
case 1:
obj.handleuserAdded(list)
case -1:
obj.handleUserRemoved(list)
}
_handleFlag = false
uLock.Unlock()
}
case err, ok := <-obj.listWatcher.Error:
if !ok || err != nil {
if obj.listWatcher != nil {
obj.removeUserListFileWatch()
}
obj.watchUserListFile()
break
}
func (m *Manager) handleUserAdded(list []string) {
var paths = m.UserList
for _, p := range list {
err := m.installUserByPath(p)
if err != nil {
logger.Errorf("Install user '%s' failed: %v", p, err)
continue
}
paths = append(paths, p)
dbus.Emit(m, "UserAdded", p)
}
m.setPropUserList(paths)
}
func (obj *Manager) handleUserInfoChanged() {
for {
select {
case <-obj.infoQuit:
return
case ev, ok := <-obj.infoWatcher.Event:
if !ok {
if obj.infoWatcher != nil {
obj.removeUserInfoFileWatch()
}
obj.watchUserInfoFile()
break
}
if ev == nil {
break
}
func (m *Manager) handleUserDeleted(list []string) {
var paths = m.UserList
for _, p := range list {
m.uninstallUser(p)
paths = deleteStrFromList(p, paths)
dbus.Emit(m, "UserDeleted", p)
}
if ok, _ := regexp.MatchString(`\.swa?px?$`, ev.Name); ok {
break
}
m.setPropUserList(paths)
}
logger.Debug("User Info Event:", ev)
ok3, _ := regexp.MatchString(ICON_SYSTEM_DIR, ev.Name)
ok4, _ := regexp.MatchString(ICON_LOCAL_DIR, ev.Name)
if ok3 || ok4 {
for _, u := range obj.pathUserMap {
u.setPropIconList(u.getPropIconList())
}
}
func compareUserList(oldList, newList []string) ([]string, int) {
var (
ret []string
oldLen = len(oldList)
newLen = len(newList)
)
if ev.IsDelete() {
obj.removeUserInfoFileWatch()
obj.watchUserInfoFile()
//break
}
ok1, _ := regexp.MatchString(ETC_GROUP, ev.Name)
if ok1 {
for _, u := range obj.pathUserMap {
u.setPropAccountType(u.getPropAccountType())
}
break
}
ok2, _ := regexp.MatchString(ETC_SHADOW, ev.Name)
if ok2 {
for _, info := range getUserInfoList() {
u, ok := obj.pathUserMap[obj.FindUserByName(info.Name)]
if !ok {
continue
}
u.setPropLocked(info.Locked)
}
break
}
ok5, _ := regexp.MatchString(ETC_LIGHTDM_CONFIG, ev.Name)
ok6, _ := regexp.MatchString(ETC_GDM_CONFIG, ev.Name)
ok7, _ := regexp.MatchString(ETC_KDM_CONFIG, ev.Name)
if ok5 || ok6 || ok7 {
for _, u := range obj.pathUserMap {
u.setPropAutomaticLogin(u.getPropAutomaticLogin())
}
break
}
case err, ok := <-obj.infoWatcher.Error:
if !ok || err != nil {
if obj.infoWatcher != nil {
obj.removeUserInfoFileWatch()
}
obj.watchUserInfoFile()
break
if oldLen < newLen {
for _, v := range newList {
if isStrInArray(v, oldList) {
continue
}
ret = append(ret, v)
}
}
}
func (obj *User) watchUserConfig() {
if obj.watcher == nil {
var err error
if obj.watcher, err = fsnotify.NewWatcher(); err != nil {
logger.Error("New watcher in newUser failed:", err)
return
return ret, userListAdded
} else if oldLen > newLen {
for _, v := range oldList {
if isStrInArray(v, newList) {
continue
}
ret = append(ret, v)
}
return ret, userListDeleted
}
obj.watcher.Watch(path.Join(USER_CONFIG_DIR, obj.UserName))
return ret, userListNotChange
}
func (obj *User) removeUserConfigWatch() {
if obj.watcher == nil {
return
}
obj.watcher.RemoveWatch(path.Join(USER_CONFIG_DIR, obj.UserName))
}
func (obj *User) handUserConfigChanged() {
for {
select {
case <-obj.quitFlag:
return
case ev, ok := <-obj.watcher.Event:
if !ok {
if obj.watcher != nil {
obj.removeUserConfigWatch()
}
obj.watchUserConfig()
break
}
if ev == nil {
break
}
if ok, _ := regexp.MatchString(`\.swa?px?$`, ev.Name); ok {
break
}
logger.Debug("User Config Event:", ev)
if ev.IsDelete() {
obj.removeUserConfigWatch()
obj.watchUserConfig()
break
}
obj.setPropIconList(obj.getPropIconList())
obj.setPropIconFile(obj.getPropIconFile())
obj.setPropBackgroundFile(obj.getPropBackgroundFile())
obj.setPropHistoryIcons(obj.getPropHistoryIcons())
case err, ok := <-obj.watcher.Error:
if !ok || err != nil {
if obj.watcher != nil {
obj.removeUserConfigWatch()
}
obj.watchUserConfig()
break
}
func deleteStrFromList(str string, list []string) []string {
var ret []string
for _, v := range list {
if v == str {
continue
}
ret = append(ret, v)
}
return ret
}

View File

@ -21,11 +21,8 @@
package accounts
import "pkg.linuxdeepin.com/dde-daemon"
import (
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/log"
"pkg.linuxdeepin.com/dde-daemon"
)
func init() {
@ -36,26 +33,3 @@ func init() {
Enable: true,
})
}
var (
logger = log.NewLogger(ACCOUNT_DEST)
)
func Start() {
logger.BeginTracing()
defer logger.EndTracing()
obj := GetManager()
if err := dbus.InstallOnSystem(obj); err != nil {
logger.Error("Install DBus Failed:", err)
return
}
obj.updateAllUserInfo()
}
func Stop() {
obj := GetManager()
obj.destroy()
dbus.UnInstallObject(obj)
}

191
accounts/manager.go Normal file
View File

@ -0,0 +1,191 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
import (
"pkg.linuxdeepin.com/dde-daemon/accounts/users"
"pkg.linuxdeepin.com/lib/dbus"
dutils "pkg.linuxdeepin.com/lib/utils"
"sync"
)
const (
userConfigDir = "/var/lib/AccountsService/users"
userIconsDir = "/var/lib/AccountsService/icons"
userCustomIconsDir = "/var/lib/AccountsService/icons/local"
userIconGuest = "/var/lib/AccountsService/icons/guest.png"
actConfigFile = "/var/lib/AccountsService/accounts.ini"
actConfigGroupGroup = "Accounts"
actConfigKeyGuest = "AllowGuest"
)
type Manager struct {
UserList []string
GuestIcon string
AllowGuest bool
UserAdded func(string)
UserDeleted func(string)
// Error(pid, action, reason)
Error func(uint32, string, string)
watcher *dutils.WatchProxy
usersMap map[string]*User
mapLocker sync.Mutex
}
func NewManager() *Manager {
var m = &Manager{}
m.usersMap = make(map[string]*User)
m.setPropGuestIcon(userIconGuest)
m.setPropAllowGuest(isGuestUserEnabled())
m.newUsers(getUserPaths())
m.watcher = dutils.NewWatchProxy()
if m.watcher != nil {
m.watcher.SetFileList(m.getWatchFiles())
m.watcher.SetEventHandler(m.handleFileChanged)
go m.watcher.StartWatch()
}
return m
}
func (m *Manager) destroy() {
if m.watcher != nil {
m.watcher.EndWatch()
m.watcher = nil
}
m.uninstallUsers(m.UserList)
dbus.UnInstallObject(m)
}
func (m *Manager) newUsers(list []string) {
var paths []string
for _, p := range list {
u, err := NewUser(p)
if err != nil {
logger.Errorf("New user '%s' failed: %v", p, err)
continue
}
paths = append(paths, p)
m.mapLocker.Lock()
m.usersMap[p] = u
m.mapLocker.Unlock()
}
m.setPropUserList(paths)
}
func (m *Manager) installUsers() {
m.mapLocker.Lock()
defer m.mapLocker.Unlock()
for _, u := range m.usersMap {
err := dbus.InstallOnSystem(u)
if err != nil {
logger.Errorf("Install user '%s' failed: %v",
u.Uid, err)
continue
}
}
}
func (m *Manager) uninstallUsers(list []string) {
for _, p := range list {
m.uninstallUser(p)
}
}
func (m *Manager) installUserByPath(userPath string) error {
u, err := NewUser(userPath)
if err != nil {
return err
}
err = dbus.InstallOnSystem(u)
if err != nil {
return err
}
m.mapLocker.Lock()
defer m.mapLocker.Unlock()
m.usersMap[userPath] = u
return nil
}
func (m *Manager) uninstallUser(userPath string) {
m.mapLocker.Lock()
defer m.mapLocker.Unlock()
u, ok := m.usersMap[userPath]
if !ok {
logger.Debug("Invalid user path:", userPath)
return
}
delete(m.usersMap, userPath)
u.destroy()
}
func (m *Manager) polkitAuthManagerUser(pid uint32, action string) error {
err := polkitAuthManagerUser(pid)
if err != nil {
triggerSigErr(pid, action, err.Error())
return err
}
return nil
}
func getUserPaths() []string {
infos, err := users.GetHumanUserInfos()
if err != nil {
return nil
}
var paths []string
for _, info := range infos {
paths = append(paths, userDBusPath+info.Uid)
}
return paths
}
func isGuestUserEnabled() bool {
v, exist := dutils.ReadKeyFromKeyFile(actConfigFile,
actConfigGroupGroup, actConfigKeyGuest, true)
if !exist {
return false
}
ret, ok := v.(bool)
if !ok {
return false
}
return ret
}

168
accounts/manager_ifc.go Normal file
View File

@ -0,0 +1,168 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
import (
"fmt"
"math/rand"
"pkg.linuxdeepin.com/dde-daemon/accounts/checkers"
"pkg.linuxdeepin.com/dde-daemon/accounts/users"
"pkg.linuxdeepin.com/lib/dbus"
dutils "pkg.linuxdeepin.com/lib/utils"
"time"
)
func (m *Manager) CreateUser(dbusMsg dbus.DMessage,
name, fullname string, ty int32) error {
pid := dbusMsg.GetSenderPID()
err := m.polkitAuthManagerUser(pid, "CreateUser")
if err != nil {
return err
}
// Avoid dde-control-center UI block
go func() {
err := users.CreateUser(name, fullname, "", ty)
if err != nil {
logger.Warningf("DoAction: create user '%s' failed: %v\n",
name, err)
triggerSigErr(pid, "CreateUser", err.Error())
return
}
err = users.SetUserType(ty, name)
if err != nil {
logger.Warningf("DoAction: set user type '%s' failed: %v\n",
name, err)
}
}()
return nil
}
func (m *Manager) DeleteUser(dbusMsg dbus.DMessage,
name string, rmFiles bool) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := m.polkitAuthManagerUser(pid, "DeleteUser")
if err != nil {
return false, err
}
go func() {
err := users.DeleteUser(rmFiles, name)
if err != nil {
logger.Warningf("DoAction: delete user '%s' failed: %v\n",
name, err)
triggerSigErr(pid, "DeleteUser", err.Error())
return
}
//delete user config and icons
if !rmFiles {
return
}
clearUserDatas(name)
}()
return true, nil
}
func (m *Manager) FindUserById(uid string) (string, error) {
userPath := userDBusPath + uid
for _, v := range m.UserList {
if v == userPath {
return v, nil
}
}
return "", fmt.Errorf("Invalid uid: %s", uid)
}
func (m *Manager) FindUserByName(name string) (string, error) {
info, err := users.GetUserInfoByName(name)
if err != nil {
return "", err
}
return m.FindUserById(info.Uid)
}
func (m *Manager) RandUserIcon() (string, bool, error) {
icons := getUserStandardIcons()
if len(icons) == 0 {
return "", false, fmt.Errorf("Did not find any user icons")
}
rand.Seed(time.Now().UnixNano())
idx := rand.Intn(len(icons))
return icons[idx], true, nil
}
func (m *Manager) IsUsernameValid(name string) (bool, string, int32) {
info := checkers.CheckUsernameValid(name)
if info == nil {
return true, "", 0
}
return false, info.Error.Error(), int32(info.Code)
}
func (m *Manager) IsPasswordValid(passwd string) bool {
return true
}
func (m *Manager) AllowGuestAccount(dbusMsg dbus.DMessage, allow bool) error {
pid := dbusMsg.GetSenderPID()
err := m.polkitAuthManagerUser(pid, "AllowGuestAccount")
if err != nil {
return err
}
if allow == isGuestUserEnabled() {
return nil
}
success := dutils.WriteKeyToKeyFile(actConfigFile,
actConfigGroupGroup, actConfigKeyGuest, allow)
if !success {
reason := "Enable guest user failed"
triggerSigErr(pid, "AllowGuestAccount", reason)
return fmt.Errorf(reason)
}
m.setPropAllowGuest(allow)
return nil
}
func (m *Manager) CreateGuestAccount() (string, error) {
name, err := users.CreateGuestUser()
if err != nil {
return "", err
}
info, err := users.GetUserInfoByName(name)
if err != nil {
return "", err
}
return userDBusPath + info.Uid, nil
}

View File

@ -22,30 +22,42 @@
package accounts
import (
C "launchpad.net/gocheck"
"testing"
"pkg.linuxdeepin.com/lib/dbus"
)
type testWrap struct{}
const (
dbusSender = "com.deepin.daemon.Accounts"
dbusPath = "/com/deepin/daemon/Accounts"
dbusIFC = "com.deepin.daemon.Accounts"
)
func Test(t *testing.T) {
C.TestingT(t)
func (m *Manager) GetDBusInfo() dbus.DBusInfo {
return dbus.DBusInfo{
Dest: dbusSender,
ObjectPath: dbusPath,
Interface: dbusIFC,
}
}
func init() {
C.Suite(&testWrap{})
func (m *Manager) setPropUserList(list []string) {
m.UserList = list
dbus.NotifyChange(m, "UserList")
}
func (*testWrap) TestNewUserShell(c *C.C) {
shell, err := getNewUserDefaultShell("testdata/adduser.conf")
c.Check(err, C.Not(C.NotNil))
c.Check(shell, C.Equals, "/bin/zsh")
func (m *Manager) setPropGuestIcon(icon string) {
if icon == m.GuestIcon {
return
}
shell, err = getNewUserDefaultShell("testdata/adduser1.conf")
c.Check(err, C.Not(C.NotNil))
c.Check(shell, C.Equals, "")
shell, err = getNewUserDefaultShell("testdata/xxxxxxx")
c.Check(err, C.NotNil)
c.Check(shell, C.Equals, "")
m.GuestIcon = icon
dbus.NotifyChange(m, "GuestIcon")
}
func (m *Manager) setPropAllowGuest(allow bool) {
if m.AllowGuest == allow {
return
}
m.AllowGuest = allow
dbus.NotifyChange(m, "AllowGuest")
}

85
accounts/polkit.go Normal file
View File

@ -0,0 +1,85 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
import (
"dbus/org/freedesktop/policykit1"
"fmt"
"pkg.linuxdeepin.com/lib/dbus"
)
const (
polkitSender = "org.freedesktop.PolicyKit1"
polkitPath = "/org/freedesktop/PolicyKit1/Authority"
)
type polkitSubject struct {
/*
* The following kinds of subjects are known:
* Unix Process: should be set to unix-process with keys
* pid (of type uint32) and
* start-time (of type uint64)
* Unix Session: should be set to unix-session with the key
* session-id (of type string)
* System Bus Name: should be set to system-bus-name with the key
* name (of type string)
*/
SubjectKind string
SubjectDetails map[string]dbus.Variant
}
func polkitAuthWithPid(actionId string, pid uint32) (bool, error) {
polkit, err := policykit1.NewAuthority(polkitSender,
polkitPath)
if err != nil {
return false, err
}
var subject polkitSubject
subject.SubjectKind = "unix-process"
subject.SubjectDetails = make(map[string]dbus.Variant)
subject.SubjectDetails["pid"] = dbus.MakeVariant(uint32(pid))
subject.SubjectDetails["start-time"] = dbus.MakeVariant(uint64(0))
var details = make(map[string]string)
details[""] = ""
var flg uint32 = 1
var cancelId string
ret, err := polkit.CheckAuthorization(subject,
actionId, details, flg, cancelId)
if err != nil {
return false, err
}
//If ret[0].(bool) == true, successful.
if len(ret) == 0 {
return false, fmt.Errorf("No results returned")
}
v, ok := ret[0].(bool)
if !ok {
return false, fmt.Errorf("Invalid result type")
}
return v, nil
}

View File

@ -1,85 +0,0 @@
# /etc/adduser.conf: `adduser' configuration.
# See adduser(8) and adduser.conf(5) for full documentation.
# The DSHELL variable specifies the default login shell on your
# system.
DSHELL=/bin/zsh
# The DHOME variable specifies the directory containing users' home
# directories.
DHOME=/home
# If GROUPHOMES is "yes", then the home directories will be created as
# /home/groupname/user.
GROUPHOMES=no
# If LETTERHOMES is "yes", then the created home directories will have
# an extra directory - the first letter of the user name. For example:
# /home/u/user.
LETTERHOMES=no
# The SKEL variable specifies the directory containing "skeletal" user
# files; in other words, files such as a sample .profile that will be
# copied to the new user's home directory when it is created.
SKEL=/etc/skel
# FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs
# for dynamically allocated administrative and system accounts/groups.
# Please note that system software, such as the users allocated by the base-passwd
# package, may assume that UIDs less than 100 are unallocated.
FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999
FIRST_SYSTEM_GID=100
LAST_SYSTEM_GID=999
# FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically
# allocated user accounts/groups.
FIRST_UID=1000
LAST_UID=29999
FIRST_GID=1000
LAST_GID=29999
# The USERGROUPS variable can be either "yes" or "no". If "yes" each
# created user will be given their own group to use as a default. If
# "no", each created user will be placed in the group whose gid is
# USERS_GID (see below).
USERGROUPS=yes
# If USERGROUPS is "no", then USERS_GID should be the GID of the group
# `users' (or the equivalent group) on your system.
USERS_GID=100
# If DIR_MODE is set, directories will be created with the specified
# mode. Otherwise the default mode 0755 will be used.
DIR_MODE=0755
# If SETGID_HOME is "yes" home directories for users with their own
# group the setgid bit will be set. This was the default for
# versions << 3.13 of adduser. Because it has some bad side effects we
# no longer do this per default. If you want it nevertheless you can
# still set it here.
SETGID_HOME=no
# If QUOTAUSER is set, a default quota will be set from that user with
# `edquota -p QUOTAUSER newuser'
QUOTAUSER=""
# If SKEL_IGNORE_REGEX is set, adduser will ignore files matching this
# regular expression when creating a new home directory
SKEL_IGNORE_REGEX="dpkg-(old|new|dist|save)"
# Set this if you want the --add_extra_groups option to adduser to add
# new users to other groups.
# This is the list of groups that new non-system users will be added to
# Default:
#EXTRA_GROUPS="dialout cdrom floppy audio video plugdev users"
# If ADD_EXTRA_GROUPS is set to something non-zero, the EXTRA_GROUPS
# option above will be default behavior for adding new, non-system users
#ADD_EXTRA_GROUPS=1
# check user and group names also against this regular expression.
#NAME_REGEX="^[a-z][-a-z0-9_]*\$"

View File

@ -1,85 +0,0 @@
# /etc/adduser.conf: `adduser' configuration.
# See adduser(8) and adduser.conf(5) for full documentation.
# The DSHELL variable specifies the default login shell on your
# system.
DSHELL=
# The DHOME variable specifies the directory containing users' home
# directories.
DHOME=/home
# If GROUPHOMES is "yes", then the home directories will be created as
# /home/groupname/user.
GROUPHOMES=no
# If LETTERHOMES is "yes", then the created home directories will have
# an extra directory - the first letter of the user name. For example:
# /home/u/user.
LETTERHOMES=no
# The SKEL variable specifies the directory containing "skeletal" user
# files; in other words, files such as a sample .profile that will be
# copied to the new user's home directory when it is created.
SKEL=/etc/skel
# FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs
# for dynamically allocated administrative and system accounts/groups.
# Please note that system software, such as the users allocated by the base-passwd
# package, may assume that UIDs less than 100 are unallocated.
FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999
FIRST_SYSTEM_GID=100
LAST_SYSTEM_GID=999
# FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically
# allocated user accounts/groups.
FIRST_UID=1000
LAST_UID=29999
FIRST_GID=1000
LAST_GID=29999
# The USERGROUPS variable can be either "yes" or "no". If "yes" each
# created user will be given their own group to use as a default. If
# "no", each created user will be placed in the group whose gid is
# USERS_GID (see below).
USERGROUPS=yes
# If USERGROUPS is "no", then USERS_GID should be the GID of the group
# `users' (or the equivalent group) on your system.
USERS_GID=100
# If DIR_MODE is set, directories will be created with the specified
# mode. Otherwise the default mode 0755 will be used.
DIR_MODE=0755
# If SETGID_HOME is "yes" home directories for users with their own
# group the setgid bit will be set. This was the default for
# versions << 3.13 of adduser. Because it has some bad side effects we
# no longer do this per default. If you want it nevertheless you can
# still set it here.
SETGID_HOME=no
# If QUOTAUSER is set, a default quota will be set from that user with
# `edquota -p QUOTAUSER newuser'
QUOTAUSER=""
# If SKEL_IGNORE_REGEX is set, adduser will ignore files matching this
# regular expression when creating a new home directory
SKEL_IGNORE_REGEX="dpkg-(old|new|dist|save)"
# Set this if you want the --add_extra_groups option to adduser to add
# new users to other groups.
# This is the list of groups that new non-system users will be added to
# Default:
#EXTRA_GROUPS="dialout cdrom floppy audio video plugdev users"
# If ADD_EXTRA_GROUPS is set to something non-zero, the EXTRA_GROUPS
# option above will be default behavior for adding new, non-system users
#ADD_EXTRA_GROUPS=1
# check user and group names also against this regular expression.
#NAME_REGEX="^[a-z][-a-z0-9_]*\$"

View File

@ -22,263 +22,233 @@
package accounts
import (
"github.com/howeyc/fsnotify"
"io/ioutil"
"math/rand"
"fmt"
"os"
"path"
"pkg.linuxdeepin.com/dde-daemon/accounts/users"
"pkg.linuxdeepin.com/lib/dbus"
dutils "pkg.linuxdeepin.com/lib/utils"
"regexp"
"strings"
)
const (
UserTypeStandard int32 = iota
UserTypeAdmin
)
const (
defaultUserIcon = "/var/lib/AccountsService/icons/1.png"
defaultUserBackground = "/usr/share/backgrounds/default_background.jpg"
)
type User struct {
UserName string
Uid string
Gid string
UserName string
HomeDir string
Shell string
IconFile string
BackgroundFile string
AutomaticLogin bool
AccountType int32
Locked bool
LoginTime uint64
HistoryIcons []string
IconList []string
objectPath string
watcher *fsnotify.Watcher
quitFlag chan bool
AutomaticLogin bool
AccountType int32
LoginTime uint64
IconList []string
HistoryIcons []string
}
func addUserToAdmList(name string) bool {
tmps := []string{}
tmps = append(tmps, "-a")
tmps = append(tmps, name)
tmps = append(tmps, "sudo")
return execCommand(CMD_GPASSWD, tmps)
}
func deleteUserFromAdmList(name string) bool {
tmps := []string{}
tmps = append(tmps, "-d")
tmps = append(tmps, name)
tmps = append(tmps, "sudo")
return execCommand(CMD_GPASSWD, tmps)
}
func getRandUserIcon() string {
list := getIconList(ICON_SYSTEM_DIR)
l := len(list)
if l <= 0 {
return ""
}
index := rand.Int31n(int32(l))
return list[index]
}
func getIconList(dir string) []string {
iconfd, err := os.Open(dir)
func NewUser(userPath string) (*User, error) {
info, err := users.GetUserInfoByUid(getUidFromUserPath(userPath))
if err != nil {
logger.Warningf("Open '%s' failed: %v",
dir, err)
return nil
return nil, err
}
names, _ := iconfd.Readdirnames(0)
list := []string{}
for _, v := range names {
if strings.Contains(v, "guest") {
continue
}
var u = &User{}
u.setPropString(&u.UserName, "UserName", info.Name)
u.setPropString(&u.Uid, "Uid", info.Uid)
u.setPropString(&u.Gid, "Gid", info.Gid)
u.setPropString(&u.HomeDir, "HomeDir", info.Home)
u.setPropString(&u.Shell, "Shell", info.Shell)
u.setPropString(&u.IconFile, "IconFile", "")
u.setPropString(&u.BackgroundFile, "BackgroundFile", "")
tmp := strings.ToLower(v)
//ok, _ := regexp.MatchString(`jpe?g$||png$||gif$`, tmp)
ok1, _ := regexp.MatchString(`\.jpe?g$`, tmp)
ok2, _ := regexp.MatchString(`\.png$`, tmp)
ok3, _ := regexp.MatchString(`\.gif$`, tmp)
if ok1 || ok2 || ok3 {
list = append(list, path.Join(dir, v))
}
u.setPropBool(&u.AutomaticLogin, "AutomaticLogin",
users.IsAutoLoginUser(info.Name))
u.updatePropLocked()
u.updatePropAccountType()
u.setPropStrv(&u.IconList, "IconList", u.getAllIcons())
kFile, err := dutils.NewKeyFileFromFile(
path.Join(userConfigDir, info.Name))
if err != nil {
//Create user config file
u.setPropString(&u.IconFile, "IconFile", defaultUserIcon)
u.setPropString(&u.BackgroundFile, "BackgroundFile", defaultUserBackground)
u.writeUserConfig()
return u, nil
}
defer kFile.Free()
var write bool = false
icon, _ := kFile.GetString("User", "Icon")
u.setPropString(&u.IconFile, "IconFile", icon)
if len(u.IconFile) == 0 {
u.setPropString(&u.IconFile, "IconFile", defaultUserIcon)
write = true
}
return list
bg, _ := kFile.GetString("User", "Background")
u.setPropString(&u.BackgroundFile, "BackgroundFile", bg)
if len(u.BackgroundFile) == 0 {
u.setPropString(&u.BackgroundFile, "BackgroundFile", defaultUserBackground)
write = true
}
if write {
u.writeUserConfig()
}
_, hisIcons, _ := kFile.GetStringList("User", "HistoryIcons")
u.setPropStrv(&u.HistoryIcons, "HistoryIcons", hisIcons)
return u, nil
}
func getAdministratorList() []string {
contents, err := ioutil.ReadFile(ETC_GROUP)
if err != nil {
logger.Errorf("ReadFile '%s' failed: %s", ETC_PASSWD, err)
return nil
func (u *User) destroy() {
u.writeUserConfig()
dbus.UnInstallObject(u)
}
func (u *User) getAllIcons() []string {
icons := getUserStandardIcons()
cusIcons := getUserCustomIcons(u.UserName)
icons = append(icons, cusIcons...)
return icons
}
func (u *User) addIconFile(icon string) (string, bool, error) {
if isStrInArray(icon, u.IconList) {
return icon, false, nil
}
list := ""
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
strs := strings.Split(line, ":")
if len(strs) != GROUP_SPLIT_LEN {
continue
}
md5, ok := dutils.SumFileMd5(icon)
if !ok {
return "", false, fmt.Errorf("Sum file '%s' md5 failed", icon)
}
if strs[0] == "sudo" {
list = strs[3]
dest := path.Join(userCustomIconsDir, u.UserName+"-"+md5)
err := os.MkdirAll(path.Dir(dest), 0755)
if err != nil {
return "", false, err
}
err = dutils.CopyFile(icon, dest)
if err != nil {
return "", false, err
}
return dest, true, nil
}
func (u *User) addHistoryIcon(icon string) {
icons := u.HistoryIcons
if isStrInArray(icon, icons) {
return
}
var list = []string{icon}
for _, v := range icons {
if len(list) >= 9 {
break
}
}
return strings.Split(list, ",")
list = append(list, v)
}
u.setPropStrv(&u.HistoryIcons, "HistoryIcons", list)
}
func setAutomaticLogin(name string) {
dsp := getDefaultDisplayManager()
logger.Debugf("Set %s Auto For: %s", name, dsp)
switch dsp {
case "lightdm":
if dutils.IsFileExist(ETC_LIGHTDM_CONFIG) {
dutils.WriteKeyToKeyFile(ETC_LIGHTDM_CONFIG,
LIGHTDM_AUTOLOGIN_GROUP,
LIGHTDM_AUTOLOGIN_USER,
name)
}
case "gdm":
if dutils.IsFileExist(ETC_GDM_CONFIG) {
dutils.WriteKeyToKeyFile(ETC_GDM_CONFIG,
GDM_AUTOLOGIN_GROUP,
GDM_AUTOLOGIN_USER,
name)
}
case "kdm":
if dutils.IsFileExist(ETC_KDM_CONFIG) {
dutils.WriteKeyToKeyFile(ETC_KDM_CONFIG,
KDM_AUTOLOGIN_GROUP,
KDM_AUTOLOGIN_ENABLE,
true)
dutils.WriteKeyToKeyFile(ETC_KDM_CONFIG,
KDM_AUTOLOGIN_GROUP,
KDM_AUTOLOGIN_USER,
name)
} else if dutils.IsFileExist(USER_KDM_CONFIG) {
dutils.WriteKeyToKeyFile(ETC_KDM_CONFIG,
KDM_AUTOLOGIN_GROUP,
KDM_AUTOLOGIN_ENABLE,
true)
dutils.WriteKeyToKeyFile(USER_KDM_CONFIG,
KDM_AUTOLOGIN_GROUP,
KDM_AUTOLOGIN_USER,
name)
}
default:
logger.Warning("No support display manager")
}
}
func isAutoLogin(username string) bool {
dsp := getDefaultDisplayManager()
//logger.Info("Display: ", dsp)
switch dsp {
case "lightdm":
if dutils.IsFileExist(ETC_LIGHTDM_CONFIG) {
v, ok := dutils.ReadKeyFromKeyFile(ETC_LIGHTDM_CONFIG,
LIGHTDM_AUTOLOGIN_GROUP,
LIGHTDM_AUTOLOGIN_USER,
"")
//logger.Info("AutoUser: ", v.(string))
//logger.Info("UserName: ", username)
if ok && v.(string) == username {
return true
}
}
case "gdm":
if dutils.IsFileExist(ETC_GDM_CONFIG) {
v, ok := dutils.ReadKeyFromKeyFile(ETC_GDM_CONFIG,
GDM_AUTOLOGIN_GROUP,
GDM_AUTOLOGIN_USER,
"")
if ok && v.(string) == username {
return true
}
}
case "kdm":
if dutils.IsFileExist(ETC_KDM_CONFIG) {
v, ok := dutils.ReadKeyFromKeyFile(ETC_KDM_CONFIG,
KDM_AUTOLOGIN_GROUP,
KDM_AUTOLOGIN_USER,
"")
if ok && v.(string) == username {
return true
}
} else if dutils.IsFileExist(USER_KDM_CONFIG) {
v, ok := dutils.ReadKeyFromKeyFile(USER_KDM_CONFIG,
KDM_AUTOLOGIN_GROUP,
KDM_AUTOLOGIN_USER,
"")
if ok && v.(string) == username {
return true
}
}
}
return false
}
func getDefaultDisplayManager() string {
contents, err := ioutil.ReadFile(ETC_DISPLAY_MANAGER)
if err != nil {
logger.Errorf("ReadFile '%s' failed: %s",
ETC_DISPLAY_MANAGER, err)
return ""
}
tmp := ""
for _, b := range contents {
if b == '\n' {
tmp += ""
func (u *User) deleteHistoryIcon(icon string) {
icons := u.HistoryIcons
var list []string
for _, v := range icons {
if v == icon {
continue
}
tmp += string(b)
list = append(list, v)
}
return path.Base(tmp)
u.setPropStrv(&u.HistoryIcons, "HistoryIcons", list)
}
func (user *User) setProps() {
info, _ := getUserInfoByPath(user.objectPath)
user.setPropUserName(info.Name)
user.setPropHomeDir(info.Home)
user.setPropShell(info.Shell)
user.setPropLocked(info.Locked)
user.setPropAutomaticLogin(user.getPropAutomaticLogin())
user.setPropAccountType(user.getPropAccountType())
user.setPropIconList(user.getPropIconList())
user.setPropIconFile(user.getPropIconFile())
user.setPropBackgroundFile(user.getPropBackgroundFile())
user.setPropHistoryIcons(user.getPropHistoryIcons())
func (u *User) writeUserConfig() error {
return doWriteUserConfig(path.Join(userConfigDir, u.UserName),
u.IconFile, u.BackgroundFile, u.HistoryIcons)
}
func newUser(path string) *User {
info, ok := getUserInfoByPath(path)
if !ok {
return nil
}
func (u *User) updatePropLocked() {
u.setPropBool(&u.Locked, "Locked", users.IsUserLocked(u.UserName))
}
obj := &User{}
obj.objectPath = info.Path
obj.Uid = info.Uid
obj.Gid = info.Gid
func (u *User) updatePropAccountType() {
if users.IsAdminUser(u.UserName) {
u.setPropInt32(&u.AccountType, "AccountType", UserTypeAdmin)
} else {
u.setPropInt32(&u.AccountType, "AccountType", UserTypeStandard)
}
}
func (u *User) accessAuthentication(pid uint32, check bool, action string) error {
var self bool
if check {
uid, _ := getUidByPid(pid)
if u.Uid == uid {
self = true
}
}
var err error
obj.watcher, err = fsnotify.NewWatcher()
if self {
err = polkitAuthChangeOwnData(pid)
} else {
err = polkitAuthManagerUser(pid)
}
if err != nil {
logger.Warning("New watcher in newUser failed:", err)
triggerSigErr(pid, action, err.Error())
return err
}
if obj.watcher != nil {
obj.quitFlag = make(chan bool)
obj.watchUserConfig()
go obj.handUserConfigChanged()
}
return obj
return nil
}
func doWriteUserConfig(config, icon, bg string, hisIcons []string) error {
if !dutils.IsFileExist(config) {
err := dutils.CreateFile(config)
if err != nil {
return err
}
}
kFile, err := dutils.NewKeyFileFromFile(config)
if err != nil {
return err
}
defer kFile.Free()
kFile.SetString("User", "Icon", icon)
kFile.SetString("User", "Background", bg)
kFile.SetStringList("User", "HistoryIcons", hisIcons)
_, content, err := kFile.ToData()
return dutils.WriteStringToFile(config, content)
}
// userPath must be composed with 'userDBusPath + uid'
func getUidFromUserPath(userPath string) string {
items := strings.Split(userPath, userDBusPath)
return items[1]
}

View File

@ -22,275 +22,297 @@
package accounts
import (
"fmt"
"os"
"path"
"pkg.linuxdeepin.com/dde-daemon/accounts/users"
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/graphic"
dutils "pkg.linuxdeepin.com/lib/utils"
"strings"
)
func (u *User) SetUserName(dbusMsg dbus.DMessage, username string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetUserName:%v",
err)
func (u *User) SetUserName(dbusMsg dbus.DMessage, name string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, false, "SetUserName")
if err != nil {
return false, err
}
go func() {
err := users.ModifyName(name, u.UserName)
if err != nil {
logger.Warning("DoAction: modify username failed:", err)
triggerSigErr(pid, "SetUserName", err.Error())
return
}
u.setPropString(&u.UserName, "UserName", name)
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.UserName != username {
u.setUserName(username)
}
return true
return true, nil
}
func (u *User) SetHomeDir(dbusMsg dbus.DMessage, dir string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetHomeDir:%v",
err)
func (u *User) SetHomeDir(dbusMsg dbus.DMessage, home string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, false, "SetHomeDir")
if err != nil {
return false, err
}
go func() {
err := users.ModifyHome(home, u.UserName)
if err != nil {
logger.Warning("DoAction: modify home failed:", err)
triggerSigErr(pid, "SetHomeDir", err.Error())
return
}
u.setPropString(&u.HomeDir, "HomeDir", home)
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.HomeDir != dir {
u.setHomeDir(dir)
}
return true
return true, nil
}
func (u *User) SetShell(dbusMsg dbus.DMessage, shell string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetShell:%v",
err)
func (u *User) SetShell(dbusMsg dbus.DMessage, shell string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, true, "SetShell")
if err != nil {
return false, err
}
go func() {
err := users.ModifyShell(shell, u.UserName)
if err != nil {
logger.Warning("DoAction: modify shell failed:", err)
triggerSigErr(pid, "SetShell", err.Error())
return
}
u.setPropString(&u.Shell, "Shell", shell)
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.Shell != shell {
u.setShell(shell)
}
return true
return true, nil
}
func (u *User) SetPassword(dbusMsg dbus.DMessage, words string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetPassword:%v",
err)
func (u *User) SetPassword(dbusMsg dbus.DMessage, words string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, false, "SetPassword")
if err != nil {
return false, err
}
go func() {
err := users.ModifyPasswd(words, u.UserName)
if err != nil {
logger.Warning("DoAction: modify passwd failed:", err)
triggerSigErr(pid, "SetPassword", err.Error())
return
}
err = users.LockedUser(false, u.UserName)
if err != nil {
logger.Warning("DoAction: unlock user failed:", err)
}
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
passwd := encodePasswd(words)
changePasswd(u.UserName, passwd)
u.setLocked(false)
return true
return true, nil
}
func (u *User) SetAutomaticLogin(dbusMsg dbus.DMessage, auto bool) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetAutomaticLogin:%v",
err)
func (u *User) SetAccountType(dbusMsg dbus.DMessage, ty int32) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, false, "SetAccountType")
if err != nil {
return false, err
}
go func() {
err := users.SetUserType(ty, u.UserName)
if err != nil {
logger.Warning("DoAction: set user type failed:", err)
triggerSigErr(pid, "SetAccountType", err.Error())
return
}
u.setPropInt32(&u.AccountType, "AccountType", ty)
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.AutomaticLogin != auto {
u.setAutomaticLogin(auto)
}
return true
return true, nil
}
func (u *User) SetAccountType(dbusMsg dbus.DMessage, t int32) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetAccountType:%v",
err)
func (u *User) SetLocked(dbusMsg dbus.DMessage, locked bool) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, false, "SetLocked")
if err != nil {
return false, err
}
go func() {
err := users.LockedUser(locked, u.UserName)
if err != nil {
logger.Warning("DoAction: locked user failed:", err)
triggerSigErr(pid, "SetLocked", err.Error())
return
}
u.setPropBool(&u.Locked, "Locked", locked)
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.AccountType != t {
u.setAccountType(t)
}
return true
return true, nil
}
func (u *User) SetLocked(dbusMsg dbus.DMessage, locked bool) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetLocked:%v",
err)
func (u *User) SetAutomaticLogin(dbusMsg dbus.DMessage, auto bool) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, false, "SetAutomaticLogin")
if err != nil {
return false, err
}
var name = u.UserName
if !auto {
name = ""
}
go func() {
err := users.SetAutoLoginUser(name)
if err != nil {
logger.Warning("DoAction: set auto login failed:", err)
triggerSigErr(pid, "SetAutomaticLogin", err.Error())
return
}
u.setPropBool(&u.AutomaticLogin, "AutomaticLogin", auto)
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.Locked != locked {
u.setLocked(locked)
}
return true
return true, nil
}
func (u *User) SetIconFile(dbusMsg dbus.DMessage, icon string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetIconFile:%v",
err)
}
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if !dutils.IsFileExist(icon) ||
!graphic.IsSupportedImage(icon) {
return false
func (u *User) SetIconFile(dbusMsg dbus.DMessage, icon string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, true, "SetIconFile")
if err != nil {
return false, err
}
if u.IconFile == icon {
return true
return true, nil
}
if !strIsInList(icon, u.IconList) {
if ok := dutils.IsFileExist(ICON_LOCAL_DIR); !ok {
if err := os.MkdirAll(ICON_LOCAL_DIR, 0755); err != nil {
return false
}
}
name := path.Base(icon)
dest := path.Join(ICON_LOCAL_DIR, u.UserName+"-"+name)
if err := dutils.CopyFile(icon, dest); err != nil {
return false
}
icon = dest
if !graphic.IsSupportedImage(icon) {
reason := fmt.Sprintf("This icon '%s' not a image", icon)
logger.Debug(reason)
triggerSigErr(pid, "SetIconFile", reason)
return false, err
}
u.setIconFile(icon)
return true
}
go func() {
target, added, err := u.addIconFile(icon)
if err != nil {
logger.Warning("Set icon failed:", err)
triggerSigErr(pid, "SetIconFile", err.Error())
return
}
func (u *User) SetBackgroundFile(dbusMsg dbus.DMessage, bg string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In SetBackgroundFile:%v",
err)
src := u.IconFile
u.setPropString(&u.IconFile, "IconFile", target)
err = u.writeUserConfig()
if err != nil {
logger.Warning("Write user config failed:", err)
triggerSigErr(pid, "SetIconFile", err.Error())
u.setPropString(&u.IconFile, "IconFile", src)
return
}
u.addHistoryIcon(src)
if added {
u.setPropStrv(&u.IconList, "IconList", u.getAllIcons())
}
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if u.BackgroundFile != bg {
u.setBackgroundFile(bg)
}
return true
return true, nil
}
func (u *User) DeleteHistoryIcon(dbusMsg dbus.DMessage, icon string) bool {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In DeleteHistoryIcon:%v",
err)
func (u *User) DeleteIconFile(dbusMsg dbus.DMessage, icon string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, true, "DeleteIconFile")
if err != nil {
return false, err
}
if !u.IsIconDeletable(icon) {
reason := "This icon is not allowed to be deleted!"
logger.Warning(reason)
triggerSigErr(pid, "DeleteHistoryIcon", reason)
return false, fmt.Errorf(reason)
}
go func() {
err := os.Remove(icon)
if err != nil {
triggerSigErr(pid, "DeleteIconFile", err.Error())
return
}
u.DeleteHistoryIcon(dbusMsg, icon)
u.setPropStrv(&u.IconList, "IconList", u.getAllIcons())
}()
return true, nil
}
func (u *User) SetBackgroundFile(dbusMsg dbus.DMessage, bg string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, true, "SetBackgroundFile")
if err != nil {
return false, err
}
if bg == u.BackgroundFile {
return true, nil
}
if !graphic.IsSupportedImage(bg) {
reason := fmt.Sprintf("This background '%s' not a image", bg)
logger.Debug(reason)
triggerSigErr(pid, "SetBackgroundFile", reason)
return false, err
}
go func() {
src := u.BackgroundFile
u.setPropString(&u.BackgroundFile, "BackgroundFile", bg)
err = u.writeUserConfig()
if err != nil {
logger.Warning("Write user config failed:", err)
triggerSigErr(pid, "SetBackgroundFile", err.Error())
u.setPropString(&u.BackgroundFile, "BackgroundFile", src)
return
}
}()
//if ok := dutils.PolkitAuthWithPid(POLKIT_MANAGER_USER,
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
return true, nil
}
func (u *User) DeleteHistoryIcon(dbusMsg dbus.DMessage, icon string) (bool, error) {
pid := dbusMsg.GetSenderPID()
err := u.accessAuthentication(pid, true, "DeleteHistoryIcon")
if err != nil {
return false, err
}
u.deleteHistoryIcon(icon)
return true
}
func (u *User) DeleteIconFile(dbusMsg dbus.DMessage, icon string) (success bool) {
defer func() {
if err := recover(); err != nil {
logger.Errorf("Recover Error In DeleteHistoryIcon:%v",
err)
}
}()
if ok := polkitAuthWithPid(POLKIT_MANAGER_USER,
dbusMsg.GetSenderPID()); !ok {
return false
}
if err := rmAllFile(icon); err != nil {
return false
}
u.deleteHistoryIcon(icon)
return true
return true, nil
}
func (u *User) IsIconDeletable(icon string) bool {
if icon == u.IconFile {
if u.IconFile == icon {
return false
}
if strings.Contains(icon, path.Join(ICON_LOCAL_DIR, u.UserName)) {
return true
if !strings.Contains(icon, path.Join(userCustomIconsDir, u.UserName)) {
return false
}
return false
return true
}
func (u *User) GetLargeIcon() string {

View File

@ -22,359 +22,50 @@
package accounts
import (
"path"
"pkg.linuxdeepin.com/lib/dbus"
dutils "pkg.linuxdeepin.com/lib/utils"
"strings"
)
func (obj *User) GetDBusInfo() dbus.DBusInfo {
const (
userDBusPath = "/com/deepin/daemon/Accounts/User"
userDBusIFC = "com.deepin.daemon.Accounts.User"
)
func (u *User) GetDBusInfo() dbus.DBusInfo {
return dbus.DBusInfo{
Dest: ACCOUNT_DEST,
ObjectPath: obj.objectPath,
Interface: USER_MANAGER_IFC,
Dest: dbusSender,
ObjectPath: userDBusPath + u.Uid,
Interface: userDBusIFC,
}
}
func (obj *User) setPropUserName(name string) {
if len(name) < 1 {
func (u *User) setPropBool(handler *bool, prop string, value bool) {
if *handler == value {
return
}
if obj.UserName != name {
obj.UserName = name
dbus.NotifyChange(obj, "UserName")
}
*handler = value
dbus.NotifyChange(u, prop)
}
func (obj *User) setPropHomeDir(homeDir string) {
if len(homeDir) < 1 {
func (u *User) setPropInt32(handler *int32, prop string, value int32) {
if *handler == value {
return
}
if obj.HomeDir != homeDir {
obj.HomeDir = homeDir
dbus.NotifyChange(obj, "HomeDir")
}
*handler = value
dbus.NotifyChange(u, prop)
}
func (obj *User) setPropShell(shell string) {
if len(shell) < 1 {
func (u *User) setPropString(handler *string, prop string, value string) {
if *handler == value {
return
}
if obj.Shell != shell {
obj.Shell = shell
dbus.NotifyChange(obj, "Shell")
}
*handler = value
dbus.NotifyChange(u, prop)
}
func (obj *User) setPropIconFile(icon string) {
if len(icon) < 1 {
return
}
if obj.IconFile != icon {
obj.IconFile = icon
dbus.NotifyChange(obj, "IconFile")
}
}
func (obj *User) setPropBackgroundFile(bg string) {
if len(bg) < 1 {
return
}
if obj.BackgroundFile != bg {
obj.BackgroundFile = bg
dbus.NotifyChange(obj, "BackgroundFile")
}
}
func (obj *User) setPropAutomaticLogin(enable bool) {
//if obj.AutomaticLogin != enable {
obj.AutomaticLogin = enable
dbus.NotifyChange(obj, "AutomaticLogin")
//}
}
func (obj *User) setPropAccountType(acctype int32) {
//if obj.AccountType != acctype {
obj.AccountType = acctype
dbus.NotifyChange(obj, "AccountType")
//}
}
func (obj *User) setPropLocked(locked bool) {
//if obj.Locked != locked {
obj.Locked = locked
dbus.NotifyChange(obj, "Locked")
//}
}
func (obj *User) setPropHistoryIcons(iconList []string) {
if !isStrListEqual(obj.HistoryIcons, iconList) {
obj.HistoryIcons = iconList
dbus.NotifyChange(obj, "HistoryIcons")
}
}
func (obj *User) setPropIconList(iconList []string) {
if !isStrListEqual(obj.IconList, iconList) {
obj.IconList = iconList
dbus.NotifyChange(obj, "IconList")
}
}
func (obj *User) getPropIconFile() string {
file := path.Join(USER_CONFIG_DIR, obj.UserName)
icon := ""
wFlag := false
if !dutils.IsFileExist(file) {
icon = getRandUserIcon()
wFlag = true
} else {
if v, ok := dutils.ReadKeyFromKeyFile(file, "User",
"Icon", ""); !ok {
icon = getRandUserIcon()
wFlag = true
} else {
icon = v.(string)
}
}
if wFlag {
dutils.WriteKeyToKeyFile(file, "User", "Icon", icon)
}
return icon
}
func (obj *User) getPropBackgroundFile() string {
file := path.Join(USER_CONFIG_DIR, obj.UserName)
bg := ""
wFlag := false
if !dutils.IsFileExist(file) {
bg = USER_DEFAULT_BG
wFlag = true
} else {
if v, ok := dutils.ReadKeyFromKeyFile(file, "User",
"Background", ""); !ok {
bg = USER_DEFAULT_BG
wFlag = true
} else {
bg = v.(string)
}
}
if wFlag {
dutils.WriteKeyToKeyFile(file, "User", "Background", bg)
}
return bg
}
func (obj *User) getPropAutomaticLogin() bool {
return isAutoLogin(obj.UserName)
}
func (obj *User) getPropAccountType() int32 {
list := getAdministratorList()
if strIsInList(obj.UserName, list) {
return ACCOUNT_TYPE_ADMINISTRATOR
}
return ACCOUNT_TYPE_STANDARD
}
func (obj *User) getPropHistoryIcons() []string {
list := []string{}
file := path.Join(USER_CONFIG_DIR, obj.UserName)
if !dutils.IsFileExist(file) {
list = append(list, obj.IconFile)
} else {
if v, ok := dutils.ReadKeyFromKeyFile(file, "User",
"HistoryIcons", []string{}); !ok {
list = append(list, obj.IconFile)
} else {
list = append(list, v.([]string)...)
}
}
tmp := []string{}
for _, v := range list {
if v == obj.IconFile {
continue
}
tmp = append(tmp, v)
}
list = tmp
return list
}
func (obj *User) getPropIconList() []string {
list := []string{}
sysList := getIconList(ICON_SYSTEM_DIR)
list = append(list, sysList...)
localList := getIconList(ICON_LOCAL_DIR)
for _, l := range localList {
if strings.Contains(l, obj.UserName+"-") {
list = append(list, l)
}
}
return list
}
func (obj *User) addHistoryIcon(iconPath string) {
file := path.Join(USER_CONFIG_DIR, obj.UserName)
if !dutils.IsFileExist(file) || !dutils.IsFileExist(iconPath) {
return
}
list, _ := dutils.ReadKeyFromKeyFile(file, "User",
"HistoryIcons", []string{})
ret := []string{}
ret = append(ret, iconPath)
cnt := 1
if list != nil {
strs := list.([]string)
as := deleteStrFromList(iconPath, strs)
for _, l := range as {
if cnt >= 10 {
break
}
if ok := dutils.IsFileExist(l); !ok {
continue
}
ret = append(ret, l)
cnt++
}
}
dutils.WriteKeyToKeyFile(file, "User", "HistoryIcons", ret)
return
}
func (obj *User) deleteHistoryIcon(iconPath string) {
file := path.Join(USER_CONFIG_DIR, obj.UserName)
if !dutils.IsFileExist(file) {
return
}
list, ok := dutils.ReadKeyFromKeyFile(file, "User",
"HistoryIcons", []string{})
if !ok || list == nil {
return
}
tmp := deleteStrFromList(iconPath, list.([]string))
dutils.WriteKeyToKeyFile(file, "User", "HistoryIcons", tmp)
return
}
func (obj *User) setUserName(name string) {
if len(name) < 1 {
return
}
args := []string{}
args = append(args, "-l")
args = append(args, name)
args = append(args, obj.UserName)
execCommand(CMD_USERMOD, args)
}
func (obj *User) setHomeDir(homeDir string) {
if len(homeDir) < 1 {
return
}
args := []string{}
args = append(args, "-m")
args = append(args, "-d")
args = append(args, homeDir)
args = append(args, obj.UserName)
execCommand(CMD_USERMOD, args)
}
func (obj *User) setShell(shell string) {
if len(shell) < 1 {
return
}
args := []string{}
args = append(args, "-s")
args = append(args, shell)
args = append(args, obj.UserName)
execCommand(CMD_USERMOD, args)
}
func (obj *User) setIconFile(icon string) {
if len(icon) < 1 {
return
}
file := path.Join(USER_CONFIG_DIR, obj.UserName)
dutils.WriteKeyToKeyFile(file, "User", "Icon", icon)
obj.addHistoryIcon(icon)
}
func (obj *User) setBackgroundFile(bg string) {
if len(bg) < 1 {
return
}
file := path.Join(USER_CONFIG_DIR, obj.UserName)
dutils.WriteKeyToKeyFile(file, "User", "Background", bg)
}
func (obj *User) setAutomaticLogin(auto bool) {
if auto {
setAutomaticLogin(obj.UserName)
} else {
setAutomaticLogin("")
}
}
func (obj *User) setAccountType(acctype int32) {
t := obj.getPropAccountType()
switch acctype {
case ACCOUNT_TYPE_ADMINISTRATOR:
if t != ACCOUNT_TYPE_ADMINISTRATOR {
ok := addUserToAdmList(obj.UserName)
if ok {
obj.setPropAccountType(acctype)
}
}
case ACCOUNT_TYPE_STANDARD:
if t == ACCOUNT_TYPE_ADMINISTRATOR {
ok := deleteUserFromAdmList(obj.UserName)
if ok {
obj.setPropAccountType(acctype)
}
}
}
}
func (obj *User) setLocked(locked bool) {
args := []string{}
if locked {
args = append(args, "-L")
args = append(args, obj.UserName)
} else {
args = append(args, "-U")
args = append(args, obj.UserName)
}
ok := execCommand(CMD_USERMOD, args)
if ok {
obj.setPropLocked(locked)
}
func (u *User) setPropStrv(handler *[]string, prop string, value []string) {
*handler = value
dbus.NotifyChange(u, prop)
}

View File

@ -1,36 +0,0 @@
root:x:0:0:root:/root:/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
messagebus:x:101:104::/var/run/dbus:/bin/false
syslog:x:102:105::/home/syslog:/bin/false
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
lightdm:x:104:110:Light Display Manager:/var/lib/lightdm:/bin/false
dnsmasq:x:105:65534:dnsmasq,,,:/var/lib/misc:/bin/false
avahi-autoipd:x:106:114:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
avahi:x:107:115:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
rtkit:x:108:118:RealtimeKit,,,:/proc:/bin/false
saned:x:109:119::/home/saned:/bin/false
colord:x:110:120:colord colour management daemon,,,:/var/lib/colord:/bin/false
hplip:x:111:7:HPLIP system user,,,:/var/run/hplip:/bin/false
pulse:x:112:121:PulseAudio daemon,,,:/var/run/pulse:/bin/false
deepin-daemon:x:113:123::/home/deepin-daemon:/bin/false
nm-openconnect:x:114:124:NetworkManager OpenConnect plugin,,,:/var/lib/NetworkManager:/bin/false
wen:x:1001:1001:wen:/home/wen:/bin/zsh
test1:x:1002:1002:test1:/home/test1:/bin/bash
test2:x:1003:1003:test2:/home/test2:/bin/bash

View File

@ -1,172 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package username_checker
import (
"fmt"
"io/ioutil"
. "pkg.linuxdeepin.com/lib/gettext"
"regexp"
"strconv"
"strings"
)
const (
passwdFilePath = "/etc/passwd"
groupFilePath = "/etc/group"
)
type usernameInfo struct {
name string
id string
}
type ErrorInfo struct {
Message error
Code int32
}
var (
ErrCodeEmpty int32 = 1
ErrCodeInvalidChar int32 = 2
ErrCodeFirstNotLower int32 = 3
ErrCodeExist int32 = 4
ErrCodeSystemUsed int32 = 5
)
var (
ErrMSGEmpty error
ErrMSGInvalidChar error
ErrMSGFirstNotLower error
ErrMSGExist error
ErrMSGSystemUsed error
)
func initErrorInfo() {
ErrMSGEmpty = fmt.Errorf(Tr("Username can not be empty."))
ErrMSGInvalidChar = fmt.Errorf(Tr("Username must comprise a~z, 0~9, - or _."))
ErrMSGFirstNotLower = fmt.Errorf(Tr("The first character must be in lower case."))
ErrMSGExist = fmt.Errorf(Tr("The username exists."))
ErrMSGSystemUsed = fmt.Errorf(Tr("The username has been used by system."))
}
func CheckUsernameValid(username string) *ErrorInfo {
if ErrMSGEmpty == nil {
initErrorInfo()
}
if len(username) == 0 {
return &ErrorInfo{
Message: ErrMSGEmpty,
Code: ErrCodeEmpty,
}
}
ok, err := checkNameExist(username, passwdFilePath)
if ok {
return err
}
/**
* The username is allowed only started with a letter,
* and is composed of letters and numbers
*/
match := regexp.MustCompile(`^[a-z]`)
if !match.MatchString(username) {
return &ErrorInfo{
Message: ErrMSGFirstNotLower,
Code: ErrCodeFirstNotLower,
}
}
match = regexp.MustCompile(`^[a-z][a-z0-9_-]*$`)
if !match.MatchString(username) {
return &ErrorInfo{
Message: ErrMSGInvalidChar,
Code: ErrCodeInvalidChar,
}
}
return nil
}
func checkNameExist(name, config string) (bool, *ErrorInfo) {
infos, err := getNameListFromFile(config)
if err != nil {
return false, nil
}
exist, info := isNameInInfoList(name, infos)
if !exist {
return false, nil
}
interval, _ := strconv.ParseInt(info.id, 10, 64)
if interval < 1000 {
return true, &ErrorInfo{
Message: ErrMSGSystemUsed,
Code: ErrCodeSystemUsed,
}
} else {
return true, &ErrorInfo{
Message: ErrMSGExist,
Code: ErrCodeExist,
}
}
return false, nil
}
func getNameListFromFile(config string) ([]usernameInfo, error) {
contents, err := ioutil.ReadFile(config)
if err != nil {
return nil, err
}
var infos []usernameInfo
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
if len(line) == 0 {
continue
}
tmp := strings.Split(line, ":")
if len(tmp) < 3 {
continue
}
info := usernameInfo{name: tmp[0], id: tmp[2]}
infos = append(infos, info)
}
return infos, nil
}
func isNameInInfoList(name string, infos []usernameInfo) (bool, usernameInfo) {
for _, info := range infos {
if name == info.name {
return true, info
}
}
return false, usernameInfo{}
}

View File

@ -1,142 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package username_checker
import (
C "launchpad.net/gocheck"
"testing"
)
type testWrapper struct{}
func init() {
initErrorInfo()
C.Suite(&testWrapper{})
}
func Test(t *testing.T) {
C.TestingT(t)
}
type errorInfo struct {
name string
code int32
ret bool
}
func (*testWrapper) TestUsernameValid(c *C.C) {
var infos = []errorInfo{
{
name: "",
code: ErrCodeEmpty,
ret: true,
},
{
name: "Asdf",
code: ErrCodeFirstNotLower,
ret: true,
},
{
name: "root",
code: ErrCodeSystemUsed,
ret: true,
},
{
name: "xx12$%",
code: ErrCodeInvalidChar,
ret: true,
},
{
name: "0",
code: ErrCodeFirstNotLower,
ret: true,
},
{
name: "A",
code: ErrCodeFirstNotLower,
ret: true,
},
{
name: "-",
code: ErrCodeFirstNotLower,
ret: true,
},
{
name: "_",
code: ErrCodeFirstNotLower,
ret: true,
},
{
name: "i",
code: -1,
ret: false,
},
{
name: "iixxx",
code: -1,
ret: false,
},
}
for _, info := range infos {
err := CheckUsernameValid(info.name)
if info.ret {
c.Check(err.Code, C.Equals, info.code)
} else {
c.Check(err, C.Not(C.NotNil))
}
}
}
func (*testWrapper) TestUsernameExist(c *C.C) {
var infos = []errorInfo{
{
name: "",
code: -1,
ret: false,
},
{
name: "root",
code: ErrCodeSystemUsed,
ret: true,
},
{
name: "wen",
code: ErrCodeExist,
ret: true,
},
{
name: "iixxx",
code: -1,
ret: false,
},
}
for _, info := range infos {
_, err := checkNameExist(info.name, "testdata/passwd")
if info.ret {
c.Check(err.Code, C.Equals, info.code)
} else {
c.Check(err, C.Not(C.NotNil))
}
}
}

View File

@ -19,27 +19,22 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package ntp
package users
import (
C "launchpad.net/gocheck"
"testing"
"os/exec"
)
type testWrapper struct{}
func init() {
C.Suite(&testWrapper{})
}
func Test(t *testing.T) {
C.TestingT(t)
}
func (*testWrapper) TestGetDateTime(c *C.C) {
_, _, err := getDateTime()
//c.Check(err, C.Not(C.NotNil))
if err != nil {
c.Skip(err.Error())
func isStrInArray(str string, array []string) bool {
for _, v := range array {
if v == str {
return true
}
}
return false
}
func doAction(cmd string) error {
return exec.Command("/bin/sh", "-c", cmd).Run()
}

62
accounts/users/guest.go Normal file
View File

@ -0,0 +1,62 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package users
import (
"fmt"
"math/rand"
"time"
)
func CreateGuestUser() (string, error) {
shell, _ := getDefaultShell(defaultConfigShell)
if len(shell) == 0 {
shell = "/bin/bash"
}
username := getGuestUserName()
var cmd = fmt.Sprintf("%s -m -d /tmp/%s -s %s -l -p %s %s",
userCmdAdd, username, shell, EncodePasswd(""), username)
err := doAction(cmd)
if err != nil {
return "", err
}
return username, nil
}
func getGuestUserName() string {
var (
seedStr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
l = len(seedStr)
name = "guest-"
)
for i := 0; i < 6; i++ {
rand.Seed(time.Now().UnixNano())
index := rand.Intn(l)
name += string(seedStr[index])
}
return name
}

216
accounts/users/list.go Normal file
View File

@ -0,0 +1,216 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package users
import (
"fmt"
"io/ioutil"
"strings"
)
const (
userFilePasswd = "/etc/passwd"
userFileShadow = "/etc/shadow"
userFileGroup = "/etc/group"
itemLenPasswd = 7
itemLenShadow = 9
itemLenGroup = 4
)
var (
invalidShells = []string{
"false",
"nologin",
}
)
type UserInfo struct {
Name string
Uid string
Gid string
Home string
Shell string
}
type UserInfos []UserInfo
func GetAllUserInfos() (UserInfos, error) {
return getUserInfosFromFile(userFilePasswd)
}
func GetHumanUserInfos() (UserInfos, error) {
infos, err := getUserInfosFromFile(userFilePasswd)
if err != nil {
return nil, err
}
infos = infos.filterUserInfos()
return infos, nil
}
func GetUserInfoByName(name string) (UserInfo, error) {
return getUserInfo(UserInfo{Name: name}, userFilePasswd)
}
func GetUserInfoByUid(uid string) (UserInfo, error) {
return getUserInfo(UserInfo{Uid: uid}, userFilePasswd)
}
func getUserInfo(condition UserInfo, file string) (UserInfo, error) {
infos, err := getUserInfosFromFile(file)
if err != nil {
return UserInfo{}, err
}
for _, info := range infos {
if info.Name == condition.Name ||
info.Uid == condition.Uid {
return info, nil
}
}
return UserInfo{}, fmt.Errorf("Invalid username or uid")
}
func getUserInfosFromFile(file string) (UserInfos, error) {
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
var infos UserInfos
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if len(line) == 0 {
continue
}
items := strings.Split(line, ":")
if len(items) != itemLenPasswd {
continue
}
info := UserInfo{
Name: items[0],
Uid: items[2],
Gid: items[3],
Home: items[5],
Shell: items[6],
}
infos = append(infos, info)
}
return infos, nil
}
func (infos UserInfos) GetUserNames() []string {
var names []string
for _, info := range infos {
names = append(names, info.Name)
}
return names
}
func (infos UserInfos) filterUserInfos() UserInfos {
var tmp UserInfos
for _, info := range infos {
if !info.isHumanUser(userFileShadow) {
continue
}
tmp = append(tmp, info)
}
return tmp
}
func (info UserInfo) isHumanUser(config string) bool {
if info.Name == "root" {
return false
}
if !info.isHumanViaShell() {
return false
}
if !info.isHumanViaShadow(config) {
return false
}
return true
}
func (info UserInfo) isHumanViaShell() bool {
items := strings.Split(info.Shell, "/")
if len(items) == 0 {
return true
}
if isStrInArray(items[len(items)-1], invalidShells) {
return false
}
return true
}
func (info UserInfo) isHumanViaShadow(config string) bool {
content, err := ioutil.ReadFile(config)
if err != nil {
return false
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if len(line) == 0 {
continue
}
items := strings.Split(line, ":")
if len(items) != itemLenShadow {
continue
}
if items[0] != info.Name {
continue
}
pw := items[1]
// user was locked
if pw[0] == '!' {
return true
}
// 加盐密码最短为13
if pw[0] == '*' || len(pw) < 13 {
break
}
return true
}
return false
}

325
accounts/users/manager.go Normal file
View File

@ -0,0 +1,325 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package users
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"path"
dutils "pkg.linuxdeepin.com/lib/utils"
"regexp"
)
const (
UserTypeStandard int32 = iota
UserTypeAdmin
)
const (
userCmdAdd = "useradd"
userCmdDelete = "userdel"
userCmdModify = "usermod"
userCmdGroup = "gpasswd"
defaultConfigShell = "/etc/adduser.conf"
displayManagerDefaultConfig = "/etc/X11/default-display-manager"
lightdmDefaultConfig = "/etc/lightdm/lightdm.conf"
kdmDefaultConfig = "/usr/share/config/kdm/kdmrc"
gdmDefaultConfig = "/etc/gdm/custom.conf"
)
func CreateUser(username, fullname, shell string, ty int32) error {
if len(username) == 0 {
return errInvalidParam
}
if len(shell) == 0 {
shell, _ = getDefaultShell(defaultConfigShell)
}
var cmd = fmt.Sprintf("%s -m ", userCmdAdd)
if len(shell) != 0 {
cmd = fmt.Sprintf("%s -s %s", cmd, shell)
}
if len(fullname) != 0 {
cmd = fmt.Sprintf("%s -c %s", cmd, fullname)
}
cmd = fmt.Sprintf("%s %s", cmd, username)
return doAction(cmd)
}
func DeleteUser(rmFiles bool, username string) error {
var cmd string
if rmFiles {
cmd = fmt.Sprintf("%s -rf %s", userCmdDelete, username)
} else {
cmd = fmt.Sprintf("%s -f %s", userCmdDelete, username)
}
return doAction(cmd)
}
func LockedUser(locked bool, username string) error {
var cmd string
if locked {
cmd = fmt.Sprintf("%s -L %s", userCmdModify, username)
} else {
cmd = fmt.Sprintf("%s -U %s", userCmdModify, username)
}
return doAction(cmd)
}
func SetUserType(ty int32, username string) error {
var cmd string
switch ty {
case UserTypeStandard:
if !IsAdminUser(username) {
return nil
}
cmd = fmt.Sprintf("%s -d %s sudo", userCmdGroup, username)
case UserTypeAdmin:
if IsAdminUser(username) {
return nil
}
cmd = fmt.Sprintf("%s -a %s sudo", userCmdGroup, username)
default:
return errInvalidParam
}
return doAction(cmd)
}
func SetAutoLoginUser(username string) error {
dm, err := getDefaultDisplayManager(displayManagerDefaultConfig)
if err != nil {
return err
}
name, _ := GetAutoLoginUser()
if name == username {
return nil
}
switch dm {
case "lightdm":
return setLightdmAutoLoginUser(username, lightdmDefaultConfig)
case "kdm":
return setKDMAutoLoginUser(username, kdmDefaultConfig)
case "gdm":
return setGDMAutoLoginUser(username, gdmDefaultConfig)
default:
return fmt.Errorf("Not supported or invalid display manager: %q", dm)
}
return nil
}
func GetAutoLoginUser() (string, error) {
dm, err := getDefaultDisplayManager(displayManagerDefaultConfig)
if err != nil {
return "", err
}
switch dm {
case "lightdm":
return getLightdmAutoLoginUser(lightdmDefaultConfig)
case "kdm":
return getKDMAutoLoginUser(kdmDefaultConfig)
case "gdm":
return getGDMAutoLoginUser(gdmDefaultConfig)
default:
return "", fmt.Errorf("Not supported or invalid display manager: %q", dm)
}
return "", nil
}
//Default config: /etc/lightdm/lightdm.conf
func getLightdmAutoLoginUser(file string) (string, error) {
if !dutils.IsFileExist(file) {
return "", fmt.Errorf("Not found this file: %s", file)
}
v, exist := dutils.ReadKeyFromKeyFile(file,
"SeatDefaults", "autologin-user", "")
if !exist {
return "", nil
}
name, ok := v.(string)
if !ok {
return "", fmt.Errorf("The value's type error.")
}
return name, nil
}
func setLightdmAutoLoginUser(name, file string) error {
success := dutils.WriteKeyToKeyFile(file,
"SeatDefaults", "autologin-user", name)
if !success {
return fmt.Errorf("Set autologin user for %q failed!", name)
}
return nil
}
//Default config: /usr/share/config/kdm/kdmrc
func getKDMAutoLoginUser(file string) (string, error) {
if !dutils.IsFileExist(file) {
return "", fmt.Errorf("Not found this file: %s", file)
}
v, exist := dutils.ReadKeyFromKeyFile(file,
"X-:0-Core", "AutoLoginEnable", true)
if !exist {
return "", nil
}
enable, ok := v.(bool)
if !ok {
return "", fmt.Errorf("The value's type error.")
}
if !enable {
return "", nil
}
v, exist = dutils.ReadKeyFromKeyFile(file,
"X-:0-Core", "AutoLoginUser", "")
if !exist {
return "", nil
}
var name string
name, ok = v.(string)
if !ok {
return "", fmt.Errorf("The value's type error.")
}
return name, nil
}
func setKDMAutoLoginUser(name, file string) error {
success := dutils.WriteKeyToKeyFile(file,
"X-:0-Core", "AutoLoginEnable", true)
if !success {
return fmt.Errorf("Set 'AutoLoginEnable' to 'true' failed!")
}
success = dutils.WriteKeyToKeyFile(file,
"X-:0-Core", "AutoLoginUser", name)
if !success {
return fmt.Errorf("Set autologin user for %q failed!", name)
}
return nil
}
//Default config: /etc/gdm/custom.conf
func getGDMAutoLoginUser(file string) (string, error) {
if !dutils.IsFileExist(file) {
return "", fmt.Errorf("Not found this file: %s", file)
}
v, exist := dutils.ReadKeyFromKeyFile(file,
"daemon", "AutomaticLogin", "")
if !exist {
return "", nil
}
name, ok := v.(string)
if !ok {
return "", fmt.Errorf("The value's type error.")
}
return name, nil
}
func setGDMAutoLoginUser(name, file string) error {
success := dutils.WriteKeyToKeyFile(file,
"daemon", "AutomaticLogin", name)
if !success {
return fmt.Errorf("Set autologin user for %q failed!", name)
}
return nil
}
//Default config: /etc/X11/default-display-manager
func getDefaultDisplayManager(file string) (string, error) {
if !dutils.IsFileExist(file) {
return "", fmt.Errorf("Not found this file: %s", file)
}
content, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
var tmp string
for _, b := range content {
if b == '\n' {
continue
}
tmp += string(b)
}
return path.Base(tmp), nil
}
// Default config: /etc/adduser.conf
func getDefaultShell(config string) (string, error) {
fp, err := os.Open(config)
if err != nil {
return "", err
}
defer fp.Close()
var (
shell string
match = regexp.MustCompile(`^DSHELL=(.*)`)
scanner = bufio.NewScanner(fp)
)
for scanner.Scan() {
line := scanner.Text()
fields := match.FindStringSubmatch(line)
if len(fields) < 2 {
continue
}
shell = fields[1]
break
}
return shell, nil
}

View File

@ -19,11 +19,12 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
/*#include <stdio.h>*/
#include <time.h>
#include <unistd.h>
#include <crypt.h>
#include "mkpasswd.h"
#include <shadow.h>
#include "passwd.h"
char *
mkpasswd (const char *words)
@ -36,12 +37,11 @@ mkpasswd (const char *words)
char *password;
int i;
/* Generate a (not very) random seed.
You should do it better than this... */
// Generate a (not very) random seed. You should do it better than this...
seed[0] = time(NULL);
seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000);
/* Turn it into printable characters from `seedchars'. */
// Turn it into printable characters from `seedchars'.
for (i = 0; i < 8; i++) {
salt[3 + i] = seedchars[(seed[i / 5] >> (i % 5) * 6) & 0x3f];
}
@ -52,18 +52,14 @@ mkpasswd (const char *words)
return password;
}
/*
int
main(int argc, char *argv[])
lock_shadow_file()
{
if (argc != 2 ) {
printf("args error\n");
return -1;
}
char *passwd = mkpasswd(argv[1]);
printf("mkpasswd: %s\n", passwd);
return 0;
return lckpwdf();
}
int
unlock_shadow_file()
{
return ulckpwdf();
}
*/

142
accounts/users/passwd.go Normal file
View File

@ -0,0 +1,142 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package users
/*
#cgo CFLAGS: -Wall -g
#cgo LDFLAGS: -lcrypt
#include <stdlib.h>
#include "passwd.h"
*/
import "C"
import (
"fmt"
"io/ioutil"
"os"
"strings"
"sync"
"unsafe"
)
var (
wLocker sync.Mutex
)
func EncodePasswd(words string) string {
cwords := C.CString(words)
defer C.free(unsafe.Pointer(cwords))
return C.GoString(C.mkpasswd(cwords))
}
// password: has been crypt
func updatePasswd(password, username string) error {
status := C.lock_shadow_file()
if status != 0 {
return fmt.Errorf("Lock shadow file failed")
}
defer C.unlock_shadow_file()
content, err := ioutil.ReadFile(userFileShadow)
if err != nil {
return err
}
lines := strings.Split(string(content), "\n")
var datas []string
var found bool
for _, line := range lines {
if len(line) == 0 {
datas = append(datas, line)
continue
}
items := strings.Split(line, ":")
if items[0] != username {
datas = append(datas, line)
continue
}
found = true
if items[1] == password {
return nil
}
var tmp string
for i, v := range items {
if i != 0 {
tmp += ":"
}
if i == 1 {
tmp += password
continue
}
tmp += v
}
datas = append(datas, tmp)
}
if !found {
return fmt.Errorf("The username not exist.")
}
return writeStrvToFile(datas, userFileShadow, 0600)
}
func writeStrvToFile(datas []string, file string, mode os.FileMode) error {
var content string
for i, v := range datas {
if i != 0 {
content += "\n"
}
content += v
}
f, err := os.Create(file + ".bak~")
if err != nil {
return err
}
defer f.Close()
wLocker.Lock()
defer wLocker.Unlock()
_, err = f.WriteString(content)
if err != nil {
return err
}
err = f.Sync()
if err != nil {
return err
}
os.Rename(file+".bak~", file)
os.Chmod(file, mode)
return nil
}

View File

@ -19,9 +19,12 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
#ifndef __MKPASSWD_H__
#define __MKPASSWD_H__
#ifndef __PASSWORD_H__
#define __PASSWORD_H__
char* mkpasswd(const char *words);
char *mkpasswd(const char *words);
int lock_shadow_file();
int unlock_shadow_file();
#endif

131
accounts/users/prop.go Normal file
View File

@ -0,0 +1,131 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package users
import (
"fmt"
"io/ioutil"
"os/exec"
"strings"
)
var (
errInvalidParam = fmt.Errorf("Invalid or empty parameter")
)
func ModifyName(newname, username string) error {
if len(newname) == 0 {
return errInvalidParam
}
var cmd = fmt.Sprintf("%s -l %s %s", userCmdModify, newname, username)
return doAction(cmd)
}
func ModifyHome(dir, username string) error {
if len(dir) == 0 {
return errInvalidParam
}
var cmd = fmt.Sprintf("%s -m -d %s %s", userCmdModify, dir, username)
return doAction(cmd)
}
func ModifyShell(shell, username string) error {
if len(shell) == 0 {
return errInvalidParam
}
var cmd = fmt.Sprintf("%s -s %s", userCmdModify, shell, username)
return doAction(cmd)
}
func ModifyPasswd(words, username string) error {
if len(words) == 0 {
return errInvalidParam
}
return updatePasswd(EncodePasswd(words), username)
}
// passwd -S username
func IsUserLocked(username string) bool {
var cmd = fmt.Sprintf("passwd -S %s", username)
output, err := exec.Command("/bin/sh", "-c", cmd).Output()
if err != nil {
return true
}
items := strings.Split(string(output), " ")
if items[1] == "L" {
return true
}
return false
}
func IsAutoLoginUser(username string) bool {
name, _ := GetAutoLoginUser()
if name == username {
return true
}
return false
}
func IsAdminUser(username string) bool {
admins, err := getAdminUserList(userFileGroup)
if err != nil {
return false
}
return isStrInArray(username, admins)
}
func getAdminUserList(file string) ([]string, error) {
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
var tmp string
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if len(line) == 0 {
continue
}
items := strings.Split(line, ":")
if len(items) != itemLenGroup {
continue
}
if items[0] != "sudo" {
continue
}
tmp = items[3]
}
return strings.Split(tmp, ","), nil
}

10
accounts/users/testdata/adduser.conf vendored Normal file
View File

@ -0,0 +1,10 @@
# /etc/adduser.conf: `adduser' configuration.
# See adduser(8) and adduser.conf(5) for full documentation.
# The DSHELL variable specifies the default login shell on your
# system.
DSHELL=/bin/zsh
# The DHOME variable specifies the directory containing users' home
# directories.
DHOME=/home

10
accounts/users/testdata/adduser1.conf vendored Normal file
View File

@ -0,0 +1,10 @@
# /etc/adduser.conf: `adduser' configuration.
# See adduser(8) and adduser.conf(5) for full documentation.
# The DSHELL variable specifies the default login shell on your
# system.
DSHELL=
# The DHOME variable specifies the directory containing users' home
# directories.
DHOME=/home

View File

@ -0,0 +1,2 @@
[daemon]
DefaultSession=deepin

View File

@ -0,0 +1,3 @@
[daemon]
DefaultSession=deepin
AutomaticLogin=wen

View File

@ -0,0 +1 @@
/usr/sbin/lightdm

View File

@ -0,0 +1,5 @@
[X-:0-Core]
AutoLoginEnable=false
AutoLoginLocked=false
AutoLoginUser=
ClientLogFile=.xsession-errors

View File

@ -0,0 +1,5 @@
[X-:0-Core]
AutoLoginEnable=true
AutoLoginLocked=false
AutoLoginUser=wen
ClientLogFile=.xsession-errors

View File

@ -0,0 +1,3 @@
[SeatDefaults]
greeter-session=lightdm-deepin-greeter
user-session=deepin

View File

@ -0,0 +1,4 @@
[SeatDefaults]
greeter-session=lightdm-deepin-greeter
user-session=deepin
autologin-user=wen

9
accounts/users/testdata/group vendored Normal file
View File

@ -0,0 +1,9 @@
voice:x:22:
cdrom:x:24:wen
floppy:x:25:wen
tape:x:26:
sudo:x:27:wen,test1
audio:x:29:pulse,wen
wen:x:1000:
test1:x:1001:
test2:x:1002:

3
accounts/users/testdata/passwd vendored Normal file
View File

@ -0,0 +1,3 @@
test1:x:1001:1001::/home/test1:/bin/bash
test2:x:1002:1002::/home/test2:/bin/bash
vbox:x:988:988:::/bin/false

4
accounts/users/testdata/shadow vendored Normal file
View File

@ -0,0 +1,4 @@
test1:$6$MaH590TL$Zx6EomT99Z4xvsoxtv3q5OtbIzdufB3ZpSGDORzwOFgcettfOou121lFE/XcTy1QS/uXidGcYoPoZiaHwWrIz.:16435:0:99999:7:::
test2:$6$/WF4tVw.$BGGgn/Vv3dFb59GKnlWP6f29WC9ZulDHHZBbqAcPNshtFjxE2RrfEJDYfLRCE4IEpPM1KGonRKjy0QM1jBJF/0:16435:0:99999:7:::
test3:*:16435:0:99999:7:::
test4:111111111111:16435:0:99999:7:::

View File

@ -0,0 +1,216 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package users
import (
C "launchpad.net/gocheck"
dutils "pkg.linuxdeepin.com/lib/utils"
"testing"
)
type testWrapper struct{}
func init() {
C.Suite(&testWrapper{})
}
func Test(t *testing.T) {
C.TestingT(t)
}
func (*testWrapper) TestGetUserInfos(c *C.C) {
var names = []string{"test1", "test2", "vbox"}
infos, err := getUserInfosFromFile("testdata/passwd")
c.Check(err, C.Equals, nil)
c.Check(len(infos), C.Equals, 3)
for i, info := range infos {
c.Check(info.Name, C.Equals, names[i])
}
}
func (*testWrapper) TestUserInfoValid(c *C.C) {
var infos = []struct {
name UserInfo
valid bool
}{
{
UserInfo{Name: "root"},
false,
},
{
UserInfo{Name: "test1", Shell: "/bin/bash"},
true,
},
{
UserInfo{Name: "test1", Shell: "/bin/false"},
false,
},
{
UserInfo{Name: "test1", Shell: "/bin/nologin"},
false,
},
{
UserInfo{Name: "test3", Shell: "/bin/bash"},
false,
},
{
UserInfo{Name: "test4", Shell: "/bin/bash"},
false,
},
}
for _, v := range infos {
c.Check(v.name.isHumanUser("testdata/shadow"), C.Equals, v.valid)
}
}
func (*testWrapper) TestFoundUserInfo(c *C.C) {
info, err := getUserInfo(UserInfo{Name: "test1"}, "testdata/passwd")
c.Check(err, C.Equals, nil)
c.Check(info.Name, C.Equals, "test1")
info, err = getUserInfo(UserInfo{Uid: "1001"}, "testdata/passwd")
c.Check(err, C.Equals, nil)
c.Check(info.Name, C.Equals, "test1")
info, err = getUserInfo(UserInfo{Name: "1006"}, "testdata/passwd")
c.Check(err, C.NotNil)
info, err = getUserInfo(UserInfo{Uid: "1006"}, "testdata/passwd")
c.Check(err, C.NotNil)
info, err = getUserInfo(UserInfo{Uid: "1006"}, "testdata/xxxxx")
c.Check(err, C.NotNil)
}
func (*testWrapper) TestAdminUser(c *C.C) {
var datas = []struct {
name string
admin bool
}{
{
name: "wen",
admin: true,
},
{
name: "test1",
admin: true,
},
{
name: "test2",
admin: false,
},
}
list, err := getAdminUserList("testdata/group")
c.Check(err, C.Equals, nil)
for _, data := range datas {
c.Check(isStrInArray(data.name, list), C.Equals, data.admin)
}
}
func (*testWrapper) TestGetAutoLoginUser(c *C.C) {
name, err := getLightdmAutoLoginUser("testdata/autologin/lightdm_autologin.conf")
c.Check(err, C.Equals, nil)
c.Check(name, C.Equals, "wen")
name, err = getLightdmAutoLoginUser("testdata/autologin/lightdm.conf")
c.Check(err, C.Equals, nil)
c.Check(name, C.Equals, "")
_, err = getLightdmAutoLoginUser("testdata/autologin/xxxxx.conf")
c.Check(err, C.Not(C.Equals), nil)
name, err = getGDMAutoLoginUser("testdata/autologin/custom_autologin.conf")
c.Check(err, C.Equals, nil)
c.Check(name, C.Equals, "wen")
name, err = getGDMAutoLoginUser("testdata/autologin/custom.conf")
c.Check(err, C.Equals, nil)
c.Check(name, C.Equals, "")
_, err = getGDMAutoLoginUser("testdata/autologin/xxxx.conf")
c.Check(err, C.Not(C.Equals), nil)
name, err = getKDMAutoLoginUser("testdata/autologin/kdmrc_autologin")
c.Check(err, C.Equals, nil)
c.Check(name, C.Equals, "wen")
name, err = getKDMAutoLoginUser("testdata/autologin/kdmrc")
c.Check(err, C.Equals, nil)
c.Check(name, C.Equals, "")
_, err = getKDMAutoLoginUser("testdata/autologin/xxxxx")
c.Check(err, C.Not(C.Equals), nil)
m, err := getDefaultDisplayManager("testdata/autologin/default-display-manager")
c.Check(err, C.Equals, nil)
c.Check(m, C.Equals, "lightdm")
_, err = getDefaultDisplayManager("testdata/autologin/xxxxx")
c.Check(err, C.Not(C.Equals), nil)
}
func (*testWrapper) TestWriteStrvData(c *C.C) {
var (
datas = []string{"123", "abc", "xyz"}
file = "/tmp/write_strv"
)
err := writeStrvToFile(datas, file, 0644)
c.Check(err, C.Equals, nil)
md5, _ := dutils.SumFileMd5(file)
c.Check(md5, C.Equals, "0b188e42e5f8d5bc5a6560ce68d5fbc6")
}
func (*testWrapper) TestGetDefaultShell(c *C.C) {
shell, err := getDefaultShell("testdata/adduser.conf")
c.Check(err, C.Equals, nil)
c.Check(shell, C.Equals, "/bin/zsh")
shell, err = getDefaultShell("testdata/adduser1.conf")
c.Check(err, C.Equals, nil)
c.Check(shell, C.Equals, "")
_, err = getDefaultShell("testdata/xxxxx.conf")
c.Check(err, C.Not(C.Equals), nil)
}
func (*testWrapper) TestStrInArray(c *C.C) {
var array = []string{"abc", "123", "xyz"}
var datas = []struct {
value string
ret bool
}{
{
value: "abc",
ret: true,
},
{
value: "xyz",
ret: true,
},
{
value: "abcd",
ret: false,
},
}
for _, data := range datas {
c.Check(isStrInArray(data.value, array), C.Equals, data.ret)
}
}

173
accounts/utils.go Normal file
View File

@ -0,0 +1,173 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package accounts
import (
"fmt"
"io/ioutil"
"os"
"path"
"pkg.linuxdeepin.com/lib/graphic"
"strings"
)
const (
polkitManagerUser = "com.deepin.daemon.accounts.user-administration"
polkitChangeOwnData = "com.deepin.daemon.accounts.change-own-user-data"
polkitSetLoginOption = "com.deepin.daemon.accounts.set-login-option"
)
type ErrCodeType int32
const (
ErrCodeUnkown ErrCodeType = iota
ErrCodeAuthFailed
ErrCodeExecFailed
ErrCodeParamInvalid
)
func (code ErrCodeType) String() string {
switch code {
case ErrCodeUnkown:
return "Unkown error"
case ErrCodeAuthFailed:
return "Policykit authentication failed"
case ErrCodeExecFailed:
return "Exec command failed"
case ErrCodeParamInvalid:
return "Invalid parameters"
}
return "Unkown error"
}
func clearUserDatas(name string) {
icons := getUserCustomIcons(name)
config := path.Join(userConfigDir, name)
icons = append(icons, config)
for _, v := range icons {
os.Remove(v)
}
}
func getUserStandardIcons() []string {
imgs, err := graphic.GetImagesInDir(userIconsDir)
if err != nil {
return nil
}
var icons []string
for _, img := range imgs {
if strings.Contains(img, "guest") {
continue
}
icons = append(icons, img)
}
return icons
}
func getUserCustomIcons(name string) []string {
return getUserIconsFromDir(userCustomIconsDir, name+"-")
}
func getUserIconsFromDir(dir, condition string) []string {
imgs, err := graphic.GetImagesInDir(dir)
if err != nil {
return nil
}
var icons []string
for _, img := range imgs {
if !strings.Contains(img, condition) {
continue
}
icons = append(icons, img)
}
return icons
}
func isStrInArray(str string, array []string) bool {
for _, v := range array {
if v == str {
return true
}
}
return false
}
func polkitAuthManagerUser(pid uint32) error {
return polkitAuthentication(polkitManagerUser, pid)
}
func polkitAuthChangeOwnData(pid uint32) error {
return polkitAuthentication(polkitChangeOwnData, pid)
}
func polkitAuthentication(action string, pid uint32) error {
success, err := polkitAuthWithPid(action, pid)
if err != nil {
return err
}
if !success {
return fmt.Errorf(ErrCodeAuthFailed.String())
}
return nil
}
const (
pidFileStatus = "/proc/%v/status"
)
func getUidByPid(pid uint32) (string, error) {
defer func() {
err := recover()
if err != nil {
fmt.Println("Recover error in getUidByPid:", err)
}
}()
var file = fmt.Sprintf(pidFileStatus, pid)
datas, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
var lines = strings.Split(string(datas), "\n")
for _, line := range lines {
if !strings.Contains(line, "Uid:") {
continue
}
strv := strings.Split(line, "\t")
return strv[1], nil
}
return "", fmt.Errorf("Invalid file: %s", file)
}

View File

@ -112,7 +112,7 @@ func (m *Manager) modifyCustomTheme(info *Theme) bool {
kFile.SetString(groupKeyComponent, themeKeyBackground, info.Background)
kFile.SetString(groupKeyComponent, themeKeyFontName, info.FontName)
kFile.SetString(groupKeyComponent, themeKeyFontMono, info.FontMono)
kFile.SetInteger(groupKeyComponent, themeKeyFontSize, int(info.FontSize))
kFile.SetInteger(groupKeyComponent, themeKeyFontSize, info.FontSize)
_, contents, err := kFile.ToData()
if err != nil {

View File

@ -87,7 +87,7 @@ func (bg *Background) GetInfoByName(name string) (PathInfo, error) {
}
func (bg *Background) Set(uri string) error {
settings := NewGSettings("com.deepin.dde.personalization")
settings := NewGSettings("com.deepin.wrap.gnome.desktop.background")
defer Unref(settings)
value := settings.GetString(settingsKeyPictureURI)

View File

@ -79,7 +79,6 @@ func NewCursorTheme(handler func([]string)) *CursorTheme {
cursor.watcher.SetEventHandler(cursor.handleEvent)
go cursor.watcher.StartWatch()
}
xsettings.InitXSettings()
// handle cursor changed by gtk+
C.handle_cursor_changed()
@ -143,7 +142,6 @@ func (cursor *CursorTheme) Destroy() {
cursor.watcher.EndWatch()
cursor.watcher = nil
xsettings.Unref()
}
@ -182,7 +180,12 @@ func (cursor *CursorTheme) GetThumbnail(theme string) string {
}
func setThemeViaXSettings(theme string) error {
return xsettings.SetString(xsettings.GtkStringCursorTheme, theme)
proxy, err := xsettings.NewXSProxy()
if err != nil {
return err
}
defer proxy.Free()
return proxy.SetString(xsettings.GtkCursorTheme, theme)
}
func fixedQtCursor(theme string) error {

View File

@ -37,7 +37,7 @@ const (
systemThumbPath = "/usr/share/personalization/thumbnail/WindowThemes"
userThumbPath = ".local/share/personalization/thumbnail/WindowThemes"
wmGSettingsSchema = "org.gnome.desktop.wm.preferences"
wmGSettingsSchema = "com.deepin.wrap.gnome.desktop.wm.preferences"
)
var (
@ -71,7 +71,6 @@ func NewGtkTheme(handler func([]string)) *GtkTheme {
gtk.watcher.SetEventHandler(gtk.handleEvent)
go gtk.watcher.StartWatch()
}
xsettings.InitXSettings()
return gtk
}
@ -123,7 +122,6 @@ func (gtk *GtkTheme) Destroy() {
gtk.watcher.EndWatch()
gtk.watcher = nil
xsettings.Unref()
}
func (gtk *GtkTheme) GetNameStrList() []string {
@ -196,7 +194,12 @@ func getThemeList(sysDirs, userDirs []PathInfo) []PathInfo {
}
func setThemeViaXSettings(theme string) error {
return xsettings.SetString(xsettings.NetStringThemeName, theme)
proxy, err := xsettings.NewXSProxy()
if err != nil {
return err
}
defer proxy.Free()
return proxy.SetString(xsettings.NetThemeName, theme)
}
func setQt4Theme(config string) error {

View File

@ -67,7 +67,6 @@ func NewIconTheme(handler func([]string)) *IconTheme {
icon.watcher.SetEventHandler(icon.handleEvent)
go icon.watcher.StartWatch()
}
xsettings.InitXSettings()
return icon
}
@ -116,7 +115,6 @@ func (icon *IconTheme) Destroy() {
icon.watcher.EndWatch()
icon.watcher = nil
xsettings.Unref()
}
func (icon *IconTheme) GetNameStrList() []string {
@ -199,7 +197,12 @@ func getThemeList(sysDirs, userDirs []PathInfo) []PathInfo {
}
func setThemeViaXSettings(theme string) error {
return xsettings.SetString(xsettings.NetStringIconTheme, theme)
proxy, err := xsettings.NewXSProxy()
if err != nil {
return err
}
defer proxy.Free()
return proxy.SetString(xsettings.NetIconTheme, theme)
}
func getDirList() []string {

View File

@ -28,13 +28,15 @@ import (
type FontManager struct {
standardList []StyleInfo
monospaceList []StyleInfo
xsProxy *xsettings.XSProxy
}
func NewFontManager() *FontManager {
font := &FontManager{}
font.xsProxy, _ = xsettings.NewXSProxy()
font.standardList, font.monospaceList = getStyleInfoList()
xsettings.InitXSettings()
return font
}

View File

@ -74,7 +74,11 @@ func (font *FontManager) Set(fontType, name string, size int32) {
return
}
xsettings.SetString(xsettings.GtkStringFontName, value)
if font.xsProxy == nil {
return
}
font.xsProxy.SetString(xsettings.GtkFontName, value)
settings := CheckAndNewGSettings(wmGSettingsSchema)
if settings != nil {
settings.SetString("titlebar-font", value)
@ -99,10 +103,13 @@ func (font *FontManager) Set(fontType, name string, size int32) {
* lcdfilter default "lcddefault"
*/
func (font *FontManager) SetXft(anti, hinting uint32, hintstyle, rgba string) {
xsettings.SetInteger(xsettings.XftBoolAntialias, anti)
xsettings.SetInteger(xsettings.XftBoolHinting, hinting)
xsettings.SetString(xsettings.XftStringHintStyle, hintstyle)
xsettings.SetString(xsettings.XftStringRgba, rgba)
if font.xsProxy == nil {
return
}
font.xsProxy.SetInteger(xsettings.XftAntialias, anti)
font.xsProxy.SetInteger(xsettings.XftHinting, hinting)
font.xsProxy.SetString(xsettings.XftHintStyle, hintstyle)
font.xsProxy.SetString(xsettings.XftRgba, rgba)
}
func (font *FontManager) GetStyleListByName(name string) []string {
@ -126,7 +133,10 @@ func (font *FontManager) GetNameList(fontType string) []string {
}
func (font *FontManager) Destroy() {
xsettings.Unref()
if font.xsProxy != nil {
font.xsProxy.Free()
font.xsProxy = nil
}
}
func setQt4Font(config, name string, size int32) {

View File

@ -42,14 +42,18 @@ func (m *Manager) listenGSettings() {
switch key {
case deepinGSKeyTheme:
m.applyTheme(m.settings.GetString(key))
case deepinGSKeyPicture:
m.Set("background", m.settings.GetString(key))
case deepinGSKeySound:
m.Set("sound", m.settings.GetString(key))
case deepinGSKeyGreeter:
m.greeter.Set(m.settings.GetString(key))
}
})
m.settings.GetString(deepinGSKeyTheme)
m.wrapSetting.Connect("changed::picture-uri", func(s *gio.Settings, key string) {
m.Set("background", m.wrapSetting.GetString(key))
})
m.wrapSetting.GetString("picture-uri")
if m.gnomeSettings == nil {
return
@ -58,6 +62,7 @@ func (m *Manager) listenGSettings() {
m.gnomeSettings.Connect("changed::picture-uri", func(s *gio.Settings, key string) {
m.bg.Set(m.gnomeSettings.GetString(key))
})
m.gnomeSettings.GetString("picture-uri")
}
func (t *Theme) handleEvent(ev *fsnotify.FileEvent) {

View File

@ -68,6 +68,7 @@ type Manager struct {
themeObjMap map[string]*Theme
settings *gio.Settings
wrapSetting *gio.Settings
gnomeSettings *gio.Settings
lock sync.Mutex
@ -102,6 +103,7 @@ func NewManager() *Manager {
m, "GreeterTheme",
m.settings, deepinGSKeyGreeter)
m.wrapSetting = NewGSettings("com.deepin.wrap.gnome.desktop.background")
m.gnomeSettings = CheckAndNewGSettings("org.gnome.desktop.background")
m.themeObjMap = make(map[string]*Theme)

View File

@ -3,8 +3,8 @@
#include <stdio.h>
#include "backlight.h"
struct udev* udev = NULL;
static struct udev_device* cached_dev = NULL;
struct udev_enumerate* cached_enumerate = NULL;
struct udev_device* filter_by_type(struct udev* udev, struct udev_list_entry* entries, const char* type)
{
@ -31,36 +31,38 @@ void set_cached_dev(struct udev_device* dev)
void init_backlight_device()
{
udev = udev_new();
struct udev_enumerate* enumerate = udev_enumerate_new(udev);
struct udev* udev = udev_new();
if (cached_enumerate != NULL) {
udev_enumerate_unref(cached_enumerate);
cached_enumerate = NULL;
}
cached_enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "backlight");
udev_enumerate_add_match_subsystem(cached_enumerate, "backlight");
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry* entries = udev_enumerate_get_list_entry(enumerate);
udev_enumerate_scan_devices(cached_enumerate);
struct udev_device* dev = filter_by_type(udev, entries, "firmware");
struct udev_list_entry* entries = udev_enumerate_get_list_entry(cached_enumerate);
if (dev == NULL){
dev = filter_by_type(udev, entries, "platform");
} else {
set_cached_dev(dev);
struct udev_device* dev = NULL;
udev_enumerate_unref(enumerate);
return;
dev = filter_by_type(udev, entries, "firmware");
if (dev != NULL) {
set_cached_dev(dev);
return;
}
if (dev == NULL){
dev = filter_by_type(udev, entries, "raw");
} else {
set_cached_dev(dev);
udev_enumerate_unref(enumerate);
return;
dev = filter_by_type(udev, entries, "raw");
if (dev != NULL) {
set_cached_dev(dev);
return;
}
set_cached_dev(dev);
udev_enumerate_unref(enumerate);
dev = filter_by_type(udev, entries, "platform");
if (dev != NULL) {
set_cached_dev(dev);
return;
}
}
double get_backlight()
@ -91,15 +93,31 @@ void set_backlight(double v)
fprintf(stderr, "set_backlight(%lf) failed\n", v);
return;
}
const char* str_max = udev_device_get_sysattr_value(cached_dev, "max_brightness");
if (str_max == NULL) {
fprintf(stderr, "set_backlight(%lf) failed\n", v);
return;
}
char str_v[1000] = {0};
sprintf(str_v, "%d", (int)(v * atoi(str_max)));
int r = udev_device_set_sysattr_value(cached_dev, "brightness", str_v);
if (r == -1) {
fprintf(stderr, "set_backlight(%lf) failed\n", v);
struct udev* udev = udev_device_get_udev(cached_dev);
struct udev_list_entry* entries = udev_enumerate_get_list_entry(cached_enumerate);
struct udev_list_entry* current;
udev_list_entry_foreach(current, entries) {
const char* name = udev_list_entry_get_name(current);
struct udev_device* dev = udev_device_new_from_syspath(udev, name);
const char* str_max = udev_device_get_sysattr_value(dev, "max_brightness");
if (str_max == NULL) {
fprintf(stderr, "get max_brightness failed(driver:%s)\n", name);
udev_device_unref(dev);
continue;
}
char str_v[1000] = {0};
sprintf(str_v, "%d", (int)(v * atoi(str_max)));
int r = udev_device_set_sysattr_value(dev, "brightness", str_v);
if (r != 0) {
fprintf(stderr, "set_backlight to %lf(%s/%s) %d failed(driver:%s)\n", v, str_v, str_max, r, name);
udev_device_unref(dev);
continue;
}
fprintf(stdout, "set_backlight to %lf(%s) (driver:%s)\n", v, str_v, name);
udev_device_unref(dev);
}
}

View File

@ -10,7 +10,7 @@ import _ "pkg.linuxdeepin.com/dde-daemon/audio"
import _ "pkg.linuxdeepin.com/dde-daemon/appearance"
import _ "pkg.linuxdeepin.com/dde-daemon/clipboard"
import _ "pkg.linuxdeepin.com/dde-daemon/datetime"
import _ "pkg.linuxdeepin.com/dde-daemon/timedate"
import _ "pkg.linuxdeepin.com/dde-daemon/mime"
import _ "pkg.linuxdeepin.com/dde-daemon/screenedge"
@ -46,8 +46,11 @@ import "pkg.linuxdeepin.com/dde-daemon"
var logger = log.NewLogger("com.deepin.daemon")
func main() {
InitI18n()
Textdomain("dde-daemon")
if !lib.UniqueOnSession("com.deepin.daemon") {
logger.Warning("There already has an dde-daemon running.")
logger.Warning("There already has a dde-daemon running.")
return
}
if len(os.Args) >= 2 {
@ -55,18 +58,16 @@ func main() {
loader.Enable(disabledModuleName, false)
}
}
logger.BeginTracing()
defer logger.EndTracing()
InitI18n()
Textdomain("dde-daemon")
C.init()
proxy.SetupProxy()
initPlugins()
initModules()
listenDaemonSettings()
loader.StartAll()
defer loader.StopAll()
go func() {
if err := dbus.Wait(); err != nil {
logger.Errorf("Lost dbus: %v", err)
@ -77,9 +78,6 @@ func main() {
}
}()
loader.Start()
defer loader.Stop()
ddeSessionRegister()
dbus.DealWithUnhandledMessage()
glib.StartLoop()

View File

@ -27,14 +27,15 @@ import (
)
var (
_pluginList = []string{
// modules should be loaded in following order
orderedModules = []string{
"inputdevices",
"screensaver",
"power",
"audio",
"appearance",
"clipboard",
"datetime",
"timedate",
"mime",
"screenedge",
"bluetooth",
@ -48,28 +49,25 @@ var (
"systeminfo",
"sessionwatcher",
}
_daemonSettings = gio.NewSettings("com.deepin.dde.daemon")
daemonSettings = gio.NewSettings("com.deepin.dde.daemon")
)
func initPlugins() {
for _, plugin := range _pluginList {
enable := _daemonSettings.GetBoolean(plugin)
if !enable {
loader.Enable(plugin, false)
}
func initModules() {
for _, name := range orderedModules {
loader.Enable(name, daemonSettings.GetBoolean(name))
}
}
func listenDaemonSettings() {
_daemonSettings.Connect("changed", func(s *gio.Settings, key string) {
enable := _daemonSettings.GetBoolean(key)
daemonSettings.Connect("changed", func(s *gio.Settings, name string) {
// gsettings key names must keep consistent with module names
enable := daemonSettings.GetBoolean(name)
loader.Enable(name, enable)
if enable {
logger.Info("-------------Enable plugin:", key)
loader.StartPlugin(key)
loader.Start(name)
} else {
logger.Info("+++++++++++++Disable plugin:", key)
loader.StopPlugin(key)
loader.Stop(name)
}
})
daemonSettings.GetBoolean("mounts")
}

View File

@ -25,12 +25,8 @@ func main() {
logger.SetRestartCommand("/usr/lib/deepin-daemon/dde-system-daemon")
// for some laptops such as ideapad, the wireless devices may be
// blocked at startup, so we try to unblock them here.
requestUnblockAllDevice()
loader.Start()
defer loader.Stop()
loader.StartAll()
defer loader.StopAll()
dbus.DealWithUnhandledMessage()

View File

@ -0,0 +1,259 @@
/**
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"path"
"pkg.linuxdeepin.com/dde-daemon/accounts/users"
"pkg.linuxdeepin.com/lib/archive"
dutils "pkg.linuxdeepin.com/lib/utils"
"regexp"
"strings"
)
const (
defaultLangName = "en_US"
defaultLangFile = "/etc/default/locale"
)
/**
* Copy user resource datas to their home directory
**/
func CopyUserDatas(user string) {
info, err := users.GetUserInfoByName(user)
if err != nil {
fmt.Printf("Get '%s' info failed: %v\n", user, err)
return
}
lang := getDefaultLang()
fmt.Println("Current LANG is :", lang)
err = copyXDGDirConfig(info.Home, lang)
if err != nil {
fmt.Printf("Copy xdg config for '%s' failed: %v\n", user, err)
}
renameXDGDirs(info.Home, lang)
err = copyDeepinManuals(info.Home, lang)
if err != nil {
fmt.Printf("Copy deepin manuals for '%s' failed: %v\n", user, err)
}
err = copySoundThemeData(info.Home, lang)
if err != nil {
fmt.Printf("Copy sound theme for '%s' failed: %v\n", user, err)
}
err = copyBroswerConfig(info.Home, lang)
if err != nil {
fmt.Printf("Copy broswer config for '%s' failed: %v\n", user, err)
}
err = changeDirOwner(user, info.Home)
if err != nil {
fmt.Printf("Change '%s' ower to '%s' failed: %v\n", info.Home, user, err)
}
}
func copyDeepinManuals(home, lang string) error {
var (
langDesc = map[string]string{
"zh_CN": "用户手册",
}
langDoc = map[string]string{
"zh_CN": "文档",
"zh_TW": "文件",
"en_US": "Documents",
}
)
src := path.Join("/usr/share/doc/deepin-manuals", lang)
if !dutils.IsFileExist(src) {
return fmt.Errorf("Not found the file or directiry: %v", src)
}
destName, ok := langDesc[lang]
if !ok {
return fmt.Errorf("The language '%s' does not support", lang)
}
docName, ok := langDoc[lang]
if !ok {
docName = "Documents"
}
doc := path.Join(home, docName)
if !dutils.IsFileExist(doc) {
err := os.MkdirAll(doc, 0755)
if err != nil {
return err
}
}
dest := path.Join(doc, destName)
if dutils.IsFileExist(dest) {
return nil
}
return dutils.SymlinkFile(src, dest)
}
func copySoundThemeData(home, lang string) error {
src := "/usr/share/deepin-sample-music/playlist.m3u"
if !dutils.IsFileExist(src) {
return fmt.Errorf("Not found the file: %v", src)
}
dir := path.Join(home, ".sample-music")
if !dutils.IsFileExist(dir) {
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
}
dest := path.Join(dir, "太歌·四季.m3u")
if dutils.IsFileExist(dest) {
return nil
}
return dutils.SymlinkFile(src, dest)
}
// Default broswer: google-chrome
func copyBroswerConfig(home, lang string) error {
dest := path.Join(home, ".config/google-chrome")
if dutils.IsFileExist(dest) {
return nil
}
var (
override = "/usr/share/deepin-default-settings/google-chrome/override-chrome-config.tar"
configLang = fmt.Sprintf("/usr/share/deepin-default-settings/google-chrome/chrome-config-%s.tar", lang)
config = "/usr/share/deepin-default-settings/google-chrome/chrome-config.tar"
broswerConfig string
)
switch {
case dutils.IsFileExist(override):
broswerConfig = override
case dutils.IsFileExist(configLang):
broswerConfig = configLang
case dutils.IsFileExist(config):
broswerConfig = config
}
if len(broswerConfig) == 0 {
return fmt.Errorf("Not found broswer configure file")
}
_, err := archive.Extracte(broswerConfig, path.Join(home, ".config"))
return err
}
func renameXDGDirs(home, lang string) {
var (
desktop = path.Join(home, "Desktop")
templates = path.Join(home, "Templates")
)
switch lang {
case "zh_CN":
if dutils.IsFileExist(desktop) {
os.Rename(desktop, path.Join(home, "桌面"))
}
if dutils.IsFileExist(templates) {
os.Rename(templates, path.Join(home, "模板"))
//dutils.CreateFile(path.Join(home, "模板", "文本文件"))
}
case "zh_TW":
if dutils.IsFileExist(desktop) {
os.Rename(desktop, path.Join(home, "桌面"))
}
if dutils.IsFileExist(templates) {
os.Rename(templates, path.Join(home, "模板"))
dutils.CreateFile(path.Join(home, "模板", "新增檔案"))
}
default:
if dutils.IsFileExist(templates) {
dutils.CreateFile(path.Join(templates, "New file"))
}
}
}
func copyXDGDirConfig(home, lang string) error {
src := path.Join("/etc/skel.locale", lang, "user-dirs.dirs")
if !dutils.IsFileExist(src) {
return fmt.Errorf("Not found this file: %s", src)
}
dest := path.Join(home, ".config", "user-dirs.dirs")
return dutils.CopyFile(src, dest)
}
func changeDirOwner(user, dir string) error {
cmd := fmt.Sprintf("chown -hR %s:%s %s", user, user, dir)
return doAction(cmd)
}
func getDefaultLang() string {
fp, err := os.Open(defaultLangFile)
if err != nil {
return defaultLangName
}
defer fp.Close()
var (
locale string
match = regexp.MustCompile(`^LANG=(.*)`)
scanner = bufio.NewScanner(fp)
)
for scanner.Scan() {
line := scanner.Text()
fields := match.FindStringSubmatch(line)
if len(fields) < 2 {
continue
}
locale = fields[1]
break
}
return strings.Split(locale, ".")[0]
}
func doAction(cmd string) error {
out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
if err != nil {
return fmt.Errorf(string(out))
}
return nil
}

69
bin/user-config/main.go Normal file
View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package main
import (
"fmt"
"os"
"os/user"
"strings"
)
func helper() {
fmt.Println("Initialize the user configuration, if the configuration files exist out directly.\n")
fmt.Println("Usage: user-config [username]")
fmt.Println("\tIf the user is not specified, will configure the current user.")
}
func getUsername(args []string) (string, bool, error) {
if len(args) == 1 {
u, err := user.Current()
if err != nil {
return "", false, err
}
return u.Username, false, nil
}
var arg = strings.ToLower(args[1])
if arg == "-h" || arg == "--help" {
return "", true, nil
}
return args[1], false, nil
}
func main() {
name, help, err := getUsername(os.Args)
if err != nil {
fmt.Println("Parse arguments failed:", err)
return
}
if help {
helper()
return
}
fmt.Printf("Start init '%s' configuration.\n", name)
CopyUserDatas(name)
fmt.Printf("Init '%s' configuration over.\n", name)
}

View File

@ -43,7 +43,7 @@ type adapter struct {
func newAdapter(apath dbus.ObjectPath) (a *adapter) {
a = &adapter{Path: apath}
a.bluezAdapter, _ = bluezNewAdapter(apath)
a.connectProeprties() // TODO
a.connectProperties()
a.adddress = a.bluezAdapter.Address.Get()
a.Alias = a.bluezAdapter.Alias.Get()
a.Powered = a.bluezAdapter.Powered.Get()
@ -66,54 +66,56 @@ func (a *adapter) notifyAdapterRemoved() {
dbus.Emit(bluetooth, "AdapterRemoved", marshalJSON(a))
bluetooth.setPropState()
}
func (a *adapter) notifyProeprtiesChanged() {
func (a *adapter) notifyPropertiesChanged() {
logger.Debug("AdapterPropertiesChanged", marshalJSON(a))
dbus.Emit(bluetooth, "AdapterPropertiesChanged", marshalJSON(a))
bluetooth.setPropState()
}
func (a *adapter) connectProeprties() {
func (a *adapter) connectProperties() {
a.bluezAdapter.Alias.ConnectChanged(func() {
a.Alias = a.bluezAdapter.Alias.Get()
a.notifyProeprtiesChanged()
a.notifyPropertiesChanged()
bluetooth.setPropAdapters()
})
a.bluezAdapter.Powered.ConnectChanged(func() {
a.Powered = a.bluezAdapter.Powered.Get()
logger.Infof("adapter powered changed %#v", a)
a.notifyProeprtiesChanged()
a.notifyPropertiesChanged()
bluetooth.setPropAdapters()
})
a.bluezAdapter.Discovering.ConnectChanged(func() {
a.Discovering = a.bluezAdapter.Discovering.Get()
a.notifyProeprtiesChanged()
a.notifyPropertiesChanged()
bluetooth.setPropAdapters()
})
a.bluezAdapter.Discoverable.ConnectChanged(func() {
a.Discoverable = a.bluezAdapter.Discoverable.Get()
a.notifyProeprtiesChanged()
a.notifyPropertiesChanged()
bluetooth.setPropAdapters()
})
a.bluezAdapter.DiscoverableTimeout.ConnectChanged(func() {
a.DiscoverableTimeout = a.bluezAdapter.DiscoverableTimeout.Get()
a.notifyProeprtiesChanged()
a.notifyPropertiesChanged()
bluetooth.setPropAdapters()
})
}
func (b *Bluetooth) addAdapter(apath dbus.ObjectPath) {
if b.isAdapterExists(apath) {
logger.Warning("repeat add adapter:", apath)
logger.Error("repeat add adapter", apath)
return
}
// initialize adapter power state
b.config.addAdapterConfig(apath)
oldPowered := b.config.getAdapterPowered(apath)
b.config.addAdapterConfig(bluezGetAdapterAddress(apath))
oldPowered := b.config.getAdapterConfigPowered(bluezGetAdapterAddress(apath))
b.SetAdapterPowered(apath, oldPowered)
if oldPowered {
b.RequestDiscovery(apath)
}
b.adaptersLock.Lock()
defer b.adaptersLock.Unlock()
a := newAdapter(apath)
b.adapters = append(b.adapters, a)
a.notifyAdapterAdded()
@ -122,22 +124,23 @@ func (b *Bluetooth) addAdapter(apath dbus.ObjectPath) {
func (b *Bluetooth) removeAdapter(apath dbus.ObjectPath) {
i := b.getAdapterIndex(apath)
if i < 0 {
logger.Warning("repeat remove adapter:", apath)
logger.Error("repeat remove adapter", apath)
return
}
b.adaptersLock.Lock()
defer b.adaptersLock.Unlock()
b.doRemoveAdapter(i)
b.setPropAdapters()
}
func (b *Bluetooth) doRemoveAdapter(i int) {
b.adapters[i].notifyAdapterRemoved()
destroyAdapter(b.adapters[i])
copy(b.adapters[i:], b.adapters[i+1:])
b.adapters[len(b.adapters)-1] = nil
b.adapters = b.adapters[:len(b.adapters)-1]
b.setPropAdapters()
}
func (b *Bluetooth) isAdapterExists(apath dbus.ObjectPath) bool {
if b.getAdapterIndex(apath) >= 0 {
return true
}
return false
}
func (b *Bluetooth) getAdapter(apath dbus.ObjectPath) (a *adapter, err error) {
i := b.getAdapterIndex(apath)
if i < 0 {
@ -145,10 +148,21 @@ func (b *Bluetooth) getAdapter(apath dbus.ObjectPath) (a *adapter, err error) {
logger.Error(err)
return
}
b.adaptersLock.Lock()
defer b.adaptersLock.Unlock()
a = b.adapters[i]
return
}
func (b *Bluetooth) isAdapterExists(apath dbus.ObjectPath) bool {
if b.getAdapterIndex(apath) >= 0 {
return true
}
return false
}
func (b *Bluetooth) getAdapterIndex(apath dbus.ObjectPath) int {
b.adaptersLock.Lock()
defer b.adaptersLock.Unlock()
for i, a := range b.adapters {
if a.Path == apath {
return i
@ -171,8 +185,18 @@ func (b *Bluetooth) RequestDiscovery(apath dbus.ObjectPath) (err error) {
err = bluezStartDiscovery(apath)
go func() {
time.Sleep(20 * time.Second)
bluezStopDiscovery(apath)
// adapter is not ready, retry again
if err != nil {
time.Sleep(3 * time.Second)
err = bluezStartDiscovery(apath)
}
if err == nil {
time.Sleep(20 * time.Second)
if b.isAdapterExists(apath) {
bluezStopDiscovery(apath)
}
}
}()
return
}
@ -181,7 +205,7 @@ func (b *Bluetooth) SetAdapterPowered(apath dbus.ObjectPath, powered bool) (err
err = bluezSetAdapterPowered(apath, powered)
if err == nil {
// save the powered state
b.config.setAdapterPowered(apath, powered)
b.config.setAdapterConfigPowered(bluezGetAdapterAddress(apath), powered)
}
return
}

View File

@ -24,6 +24,7 @@ package bluetooth
import (
sysdbus "dbus/org/freedesktop/dbus/system"
"pkg.linuxdeepin.com/lib/dbus"
"sync"
)
const (
@ -52,12 +53,14 @@ type Bluetooth struct {
objectManager *sysdbus.ObjectManager
// adapter
adapters []*adapter
Adapters string // array of adapters that marshaled by json
adaptersLock sync.Mutex
adapters []*adapter
Adapters string // array of adapters that marshaled by json
// device
devices map[dbus.ObjectPath][]*device
Devices string // device objects that marshaled by json
devicesLock sync.Mutex
devices map[dbus.ObjectPath][]*device
Devices string // device objects that marshaled by json
State uint32

View File

@ -22,6 +22,7 @@
package bluetooth
import (
"fmt"
"pkg.linuxdeepin.com/lib/dbus"
)
@ -34,13 +35,16 @@ func (b *Bluetooth) OnPropertiesChanged(name string, oldv interface{}) {
logger.Debug("OnPropertiesChanged()", name)
}
// TODO: remove
func (b *Bluetooth) DebugInfo() (info string) {
info = fmt.Sprintf("adapters: %s\ndevices: %s", marshalJSON(b.adapters), marshalJSON(b.devices))
return
}
func (b *Bluetooth) setPropAdapters() {
b.Adapters = marshalJSON(b.adapters)
dbus.NotifyChange(b, "Adapters")
}
// TODO: remove
func (b *Bluetooth) setPropDevices() {
b.Devices = marshalJSON(b.devices)
dbus.NotifyChange(b, "Devices")

View File

@ -22,19 +22,15 @@
package bluetooth
import (
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/utils"
"sync"
)
type config struct {
core utils.Config
lock sync.Mutex
Adapters map[dbus.ObjectPath]*adapterConfig // use adapter dbus path as key
Adapters map[string]*adapterConfig // use adapter hardware address as key
}
type adapterConfig struct {
lock sync.Mutex
Powered bool
}
@ -42,7 +38,7 @@ func newConfig() (c *config) {
c = &config{}
c.core.SetConfigName("bluetooth")
logger.Info("config file:", c.core.GetConfigFile())
c.Adapters = make(map[dbus.ObjectPath]*adapterConfig)
c.Adapters = make(map[string]*adapterConfig)
c.load()
c.clearSpareConfig()
return
@ -60,69 +56,73 @@ func newAdapterConfig() (ac *adapterConfig) {
}
func (c *config) clearSpareConfig() {
c.lock.Lock()
defer c.lock.Unlock()
c.core.Lock()
defer c.core.Unlock()
var addresses []string
apathes := bluezGetAdapters()
for apath, _ := range c.Adapters {
if !isDBusPathInArray(apath, apathes) {
delete(c.Adapters, apath)
for _, apath := range apathes {
addresses = append(addresses, bluezGetAdapterAddress(apath))
}
for address, _ := range c.Adapters {
if !isStringInArray(address, addresses) {
delete(c.Adapters, address)
}
}
}
func (c *config) addAdapterConfig(apath dbus.ObjectPath) {
if c.isAdapterConfigExists(apath) {
func (c *config) addAdapterConfig(address string) {
if c.isAdapterConfigExists(address) {
return
}
c.lock.Lock()
defer c.lock.Unlock()
c.Adapters[apath] = newAdapterConfig()
c.core.Lock()
defer c.core.Unlock()
c.Adapters[address] = newAdapterConfig()
}
func (c *config) removeAdapterConfig(apath dbus.ObjectPath) {
if !c.isAdapterConfigExists(apath) {
logger.Errorf("config for adapter %s not exists", apath)
func (c *config) removeAdapterConfig(address string) {
if !c.isAdapterConfigExists(address) {
logger.Errorf("config for adapter %s not exists", address)
return
}
c.lock.Lock()
defer c.lock.Unlock()
delete(c.Adapters, apath)
c.core.Lock()
defer c.core.Unlock()
delete(c.Adapters, address)
}
func (c *config) isAdapterConfigExists(apath dbus.ObjectPath) (ok bool) {
c.lock.Lock()
defer c.lock.Unlock()
_, ok = c.Adapters[apath]
func (c *config) getAdapterConfig(address string) (ac *adapterConfig, ok bool) {
c.core.Lock()
defer c.core.Unlock()
ac, ok = c.Adapters[address]
return
}
func (c *config) isAdapterConfigExists(address string) (ok bool) {
c.core.Lock()
defer c.core.Unlock()
_, ok = c.Adapters[address]
return
}
func (c *config) getAdapterPowered(apath dbus.ObjectPath) (powered bool) {
c.lock.Lock()
defer c.lock.Unlock()
ac, ok := c.Adapters[apath]
func (c *config) getAdapterConfigPowered(address string) (powered bool) {
ac, ok := c.getAdapterConfig(address)
if !ok {
return
}
powered = ac.getAdapterPowered()
c.core.Lock()
powered = ac.Powered
c.core.Unlock()
return
}
func (c *config) setAdapterPowered(apath dbus.ObjectPath, powered bool) {
ac, ok := c.Adapters[apath]
func (c *config) setAdapterConfigPowered(address string, powered bool) {
ac, ok := c.getAdapterConfig(address)
if !ok {
return
}
ac.setAdapterPowered(powered)
c.core.Lock()
ac.Powered = powered
c.core.Unlock()
c.save()
return
}
func (ac *adapterConfig) getAdapterPowered() (powered bool) {
ac.lock.Lock()
defer ac.lock.Unlock()
powered = ac.Powered
return
}
func (ac *adapterConfig) setAdapterPowered(powered bool) {
ac.lock.Lock()
defer ac.lock.Unlock()
ac.Powered = powered
return
}

View File

@ -51,7 +51,7 @@ type device struct {
connecting bool
State uint32
// optinal
// optional
Icon string
RSSI int16
}
@ -163,34 +163,33 @@ func (d *device) fixRssi() {
}
func (b *Bluetooth) addDevice(dpath dbus.ObjectPath, data map[string]dbus.Variant) {
d := newDevice(dpath, data)
if b.isDeviceExists(b.devices[d.AdapterPath], dpath) {
logger.Warning("repeat add device:", dpath)
if b.isDeviceExists(dpath) {
logger.Error("repeat add device", dpath)
return
}
d.notifyDeviceAdded()
b.devicesLock.Lock()
defer b.devicesLock.Unlock()
d := newDevice(dpath, data)
b.devices[d.AdapterPath] = append(b.devices[d.AdapterPath], d)
d.notifyDeviceAdded()
b.setPropDevices()
}
func (b *Bluetooth) removeDevice(dpath dbus.ObjectPath) {
// find adapter of the device
for apath, devices := range b.devices {
if b.isDeviceExists(devices, dpath) {
d, _ := b.getDevice(dpath)
d.notifyDeviceRemoved()
b.devices[apath] = b.doRemoveDevice(devices, dpath)
b.setPropDevices()
return
}
}
}
func (b *Bluetooth) doRemoveDevice(devices []*device, dpath dbus.ObjectPath) []*device {
i := b.getDeviceIndex(devices, dpath)
apath, i := b.getDeviceIndex(dpath)
if i < 0 {
logger.Warning("repeat remove device:", dpath)
return devices
logger.Error("repeat remove device", dpath)
return
}
b.devicesLock.Lock()
defer b.devicesLock.Unlock()
b.devices[apath] = b.doRemoveDevice(b.devices[apath], i)
b.setPropDevices()
return
}
func (b *Bluetooth) doRemoveDevice(devices []*device, i int) []*device {
devices[i].notifyDeviceRemoved()
destroyDevice(devices[i])
copy(devices[i:], devices[i+1:])
devices[len(devices)-1] = nil
@ -198,29 +197,36 @@ func (b *Bluetooth) doRemoveDevice(devices []*device, dpath dbus.ObjectPath) []*
return devices
}
func (b *Bluetooth) getDevice(dpath dbus.ObjectPath) (d *device, err error) {
for _, devices := range b.devices {
if i := b.getDeviceIndex(devices, dpath); i >= 0 {
d = devices[i]
return
}
apath, i := b.getDeviceIndex(dpath)
if i < 0 {
err = fmt.Errorf("device not found %s", dpath)
logger.Error(err)
return
}
err = fmt.Errorf("device not exists %s", dpath)
logger.Error(err)
b.devicesLock.Lock()
defer b.devicesLock.Unlock()
d = b.devices[apath][i]
return
}
func (b *Bluetooth) isDeviceExists(devices []*device, dpath dbus.ObjectPath) bool {
if b.getDeviceIndex(devices, dpath) >= 0 {
func (b *Bluetooth) isDeviceExists(dpath dbus.ObjectPath) bool {
_, i := b.getDeviceIndex(dpath)
if i >= 0 {
return true
}
return false
}
func (b *Bluetooth) getDeviceIndex(devices []*device, dpath dbus.ObjectPath) int {
for i, d := range devices {
if d.Path == dpath {
return i
func (b *Bluetooth) getDeviceIndex(dpath dbus.ObjectPath) (apath dbus.ObjectPath, index int) {
b.devicesLock.Lock()
defer b.devicesLock.Unlock()
for p, devices := range b.devices {
for i, d := range devices {
if d.Path == dpath {
return p, i
}
}
}
return -1
return "", -1
}
// GetDevices return all device objects that marshaled by json.

View File

@ -24,7 +24,6 @@ package bluetooth
import (
apidevice "dbus/com/deepin/api/device"
"encoding/json"
"pkg.linuxdeepin.com/lib/dbus"
)
func isStringInArray(str string, list []string) bool {
@ -36,15 +35,6 @@ func isStringInArray(str string, list []string) bool {
return false
}
func isDBusPathInArray(path dbus.ObjectPath, pathes []dbus.ObjectPath) bool {
for _, tmp := range pathes {
if tmp == path {
return true
}
}
return false
}
func marshalJSON(v interface{}) (strJSON string) {
byteJSON, err := json.Marshal(v)
if err != nil {

View File

@ -102,6 +102,15 @@ func bluezStopDiscovery(apath dbus.ObjectPath) (err error) {
return
}
func bluezGetAdapterAddress(apath dbus.ObjectPath) (address string) {
bluezAdapter, err := bluezNewAdapter(apath)
if err != nil {
return
}
address = bluezAdapter.Address.Get()
return
}
func bluezGetAdapterAlias(apath dbus.ObjectPath) (alias string) {
bluezAdapter, err := bluezNewAdapter(apath)
if err != nil {

View File

@ -1,123 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package datetime
import (
"io/ioutil"
"pkg.linuxdeepin.com/dde-daemon/datetime/ntp"
"pkg.linuxdeepin.com/dde-daemon/datetime/timezone"
. "pkg.linuxdeepin.com/dde-daemon/datetime/utils"
"pkg.linuxdeepin.com/lib/dbus/property"
"pkg.linuxdeepin.com/lib/gio-2.0"
"pkg.linuxdeepin.com/lib/log"
"strings"
)
const (
dbusSender = "com.deepin.daemon.DateAndTime"
dbusPath = "/com/deepin/daemon/DateAndTime"
dbusIFC = "com.deepin.daemon.DateAndTime"
gsKeyAutoSetTime = "is-auto-set"
gsKey24Hour = "is-24hour"
gsKeyUTCOffset = "utc-offset"
gsKeyTimezoneList = "user-timezone-list"
gsKeyDSTOffset = "dst-offset"
defaultTimezone = "UTC"
defaultTimezoneFile = "/etc/timezone"
defaultUTCOffset = "+00:00"
)
type DateTime struct {
NTPEnabled *property.GSettingsBoolProperty `access:"readwrite"`
Use24HourDisplay *property.GSettingsBoolProperty `access:"readwrite"`
DSTOffset *property.GSettingsIntProperty `access:"readwrite"`
UserTimezones *property.GSettingsStrvProperty
CurrentTimezone string
settings *gio.Settings
logger *log.Logger
}
func NewDateTime(l *log.Logger) *DateTime {
date := &DateTime{}
err := InitSetDateTime()
if err != nil {
return nil
}
err = ntp.InitNtpModule()
if err != nil {
return nil
}
date.logger = l
date.settings = gio.NewSettings("com.deepin.dde.datetime")
date.NTPEnabled = property.NewGSettingsBoolProperty(
date, "NTPEnabled",
date.settings, gsKeyAutoSetTime)
date.Use24HourDisplay = property.NewGSettingsBoolProperty(
date, "Use24HourDisplay",
date.settings, gsKey24Hour)
date.UserTimezones = property.NewGSettingsStrvProperty(
date, "UserTimezones",
date.settings, gsKeyTimezoneList)
date.DSTOffset = property.NewGSettingsIntProperty(
date, "DSTOffset",
date.settings, gsKeyDSTOffset)
date.setPropString(&date.CurrentTimezone,
"CurrentTimezone", getDefaultTimezone(defaultTimezoneFile))
date.AddUserTimezone(date.CurrentTimezone)
date.enableNTP(date.NTPEnabled.Get())
date.listenGSettings()
return date
}
func (date *DateTime) enableNTP(value bool) {
ntp.Enabled(value, date.CurrentTimezone)
}
func getDefaultTimezone(config string) string {
zone, err := getTimezoneFromFile(config)
if err != nil || !timezone.IsZoneValid(zone) {
return defaultTimezone
}
return zone
}
func getTimezoneFromFile(filename string) (string, error) {
contents, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
lines := strings.Split(string(contents), "\n")
return lines[0], nil
}

View File

@ -1,143 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package datetime
import (
"fmt"
"pkg.linuxdeepin.com/dde-daemon/datetime/ntp"
"pkg.linuxdeepin.com/dde-daemon/datetime/timezone"
. "pkg.linuxdeepin.com/dde-daemon/datetime/utils"
"pkg.linuxdeepin.com/lib/dbus"
)
var (
errInvalidDateArgs = fmt.Errorf("Invalid Date Argment")
)
func (date *DateTime) SetDate(year, month, day, hour, min, sec, nsec int32) error {
if !IsYearValid(year) || !IsMonthValid(month) ||
!IsDayValid(year, month, day) || !IsHourValid(hour) ||
!IsMinuteValid(min) || !IsSecondValid(sec) {
return errInvalidDateArgs
}
value := fmt.Sprintf("%v-%v-%v", year, month, day)
err := SetDate(value)
if err != nil {
Warningf(date.logger, "Set Date '%s' Failed: %v", value, err)
return err
}
value = fmt.Sprintf("%v:%v:%v", hour, min, sec)
err = SetTime(value)
if err != nil {
Warningf(date.logger, "Set Date '%s' Failed: %v", value, err)
return err
}
return nil
}
func (date *DateTime) SetTimezone(zone string) error {
err := timezone.SetTimezone(zone)
if err != nil {
Warning(date.logger, err)
return err
}
//date.settings.Reset(gsKeyDSTOffset)
date.setPropString(&date.CurrentTimezone,
"CurrentTimezone", zone)
date.AddUserTimezone(zone)
if date.NTPEnabled.Get() {
/**
* Only need to change the timezone,
* do not require immediate synchronization network time
**/
ntp.Timezone = zone
}
return nil
}
func (date *DateTime) AddUserTimezone(zone string) {
if !timezone.IsZoneValid(zone) {
Warning(date.logger, "Invalid zone:", zone)
return
}
list := date.settings.GetStrv(gsKeyTimezoneList)
if IsStrInList(zone, list) {
return
}
list = append(list, zone)
date.settings.SetStrv(gsKeyTimezoneList, list)
}
func (date *DateTime) DeleteUserTimezone(zone string) {
if !timezone.IsZoneValid(zone) {
Warning(date.logger, "Invalid zone:", zone)
return
}
list := date.settings.GetStrv(gsKeyTimezoneList)
var tmp []string
for _, s := range list {
if s == zone {
continue
}
tmp = append(tmp, s)
}
if len(tmp) == len(list) {
return
}
date.settings.SetStrv(gsKeyTimezoneList, tmp)
}
func (date *DateTime) GetZoneInfo(zone string) (timezone.ZoneInfo, error) {
info, err := timezone.GetZoneInfo(zone)
if info == nil {
return timezone.ZoneInfo{}, err
}
return *info, nil
}
func (date *DateTime) GetAllZoneInfo() []timezone.ZoneInfo {
return timezone.GetZoneInfoList()
}
func (date *DateTime) destroy() {
DestroySetDateTime()
ntp.FiniNtpModule()
date.settings.Unref()
dbus.UnInstallObject(date)
if date.logger != nil {
date.logger.EndTracing()
}
}

View File

@ -1,163 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package ntp
import (
"fmt"
"net"
. "pkg.linuxdeepin.com/dde-daemon/datetime/utils"
"sync"
"time"
)
const (
ntpHost = "0.pool.ntp.org"
)
const (
NTPStateDisabled int32 = 0
NTPStateEnabled int32 = 1
)
// update time when timezone changed
var Timezone string
var (
stateLock sync.Mutex
ntpState int32
)
func InitNtpModule() error {
ntpState = NTPStateDisabled
return InitSetDateTime()
}
func FiniNtpModule() {
DestroySetDateTime()
}
func Enabled(enable bool, zone string) {
Timezone = zone
if enable {
if ntpState == NTPStateEnabled {
go SyncNetworkTime()
return
}
stateLock.Lock()
ntpState = NTPStateEnabled
stateLock.Unlock()
go syncThread()
} else {
stateLock.Lock()
ntpState = NTPStateDisabled
stateLock.Unlock()
}
return
}
func SyncNetworkTime() bool {
for i := 0; i < 10; i++ {
dStr, tStr, err := getDateTime()
if err == nil {
SetDate(dStr)
SetTime(tStr)
return true
}
}
return false
}
func syncThread() {
for {
SyncNetworkTime()
timer := time.NewTimer(time.Minute * 10)
select {
case <-timer.C:
if ntpState == NTPStateDisabled {
return
}
}
}
}
func getDateTime() (string, string, error) {
t, err := getNetworkTime()
if err != nil {
return "", "", err
}
dStr := fmt.Sprintf("%d-%d-%d", t.Year(), t.Month(), t.Day())
tStr := fmt.Sprintf("%d:%d:%d", t.Hour(), t.Minute(), t.Second())
return dStr, tStr, nil
}
func getNetworkTime() (*time.Time, error) {
loc, err := time.LoadLocation(Timezone)
if err != nil {
return nil, err
}
time.Local = loc
raddr, err := net.ResolveUDPAddr("udp", ntpHost+":123")
if err != nil {
return nil, err
}
data := make([]byte, 48)
data[0] = 3<<3 | 3
con, err := net.DialUDP("udp", nil, raddr)
if err != nil {
return nil, err
}
defer con.Close()
_, err = con.Write(data)
if err != nil {
return nil, err
}
con.SetDeadline(time.Now().Add(5 * time.Second))
_, err = con.Read(data)
if err != nil {
return nil, err
}
var sec, frac uint64
sec = uint64(data[43]) | uint64(data[42])<<8 | uint64(data[41])<<16 |
uint64(data[40])<<24
frac = uint64(data[47]) | uint64(data[46])<<8 | uint64(data[45])<<16 |
uint64(data[44])<<24
nsec := sec * 1e9
nsec += (frac * 1e9) >> 32
t := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nsec)).Local()
return &t, nil
}

View File

@ -1 +0,0 @@
Asia/Shanghai

View File

@ -1,82 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package timezone
import (
"io/ioutil"
"strconv"
"strings"
)
type dstData struct {
zone string
dst DSTInfo
}
func parseDSTDataFile(filename string) ([]dstData, error) {
contents, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
lines := strings.Split(string(contents), "\n")
var infos []dstData
for _, line := range lines {
if len(line) == 0 {
continue
}
strs := strings.Split(line, ";")
if len(strs) != 4 {
continue
}
enter, _ := strconv.ParseInt(strs[1], 10, 64)
leave, _ := strconv.ParseInt(strs[2], 10, 64)
offset, _ := strconv.ParseInt(strs[3], 10, 64)
info := dstData{
zone: strs[0],
dst: DSTInfo{
Enter: enter,
Leave: leave,
DSTOffset: int32(offset),
},
}
infos = append(infos, info)
}
return infos, nil
}
func findDSTInfo(zone, filename string) (*DSTInfo, error) {
infos, err := parseDSTDataFile(filename)
if err != nil {
return nil, err
}
for _, info := range infos {
if info.zone == zone {
return &info.dst, nil
}
}
return nil, errNoDST
}

View File

@ -1,122 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package timezone
import (
"dbus/com/deepin/api/setdatetime"
"fmt"
"path"
dutils "pkg.linuxdeepin.com/lib/utils"
)
type DSTInfo struct {
Enter int64
Leave int64
DSTOffset int32
}
type ZoneInfo struct {
Name string
Desc string
RawOffset int32
DST DSTInfo
}
var (
ErrInvalidZone = fmt.Errorf("Invalid Timezone")
errNoDST = fmt.Errorf("The zone has not dst info")
)
const (
zoneInfoDir = "/usr/share/zoneinfo"
dstDataFile = "/usr/share/dde-daemon/dst_data"
)
func IsZoneValid(zone string) bool {
if len(zone) == 0 {
return false
}
filename := path.Join(zoneInfoDir, zone)
if dutils.IsFileExist(filename) {
return true
}
return false
}
func SetTimezone(zone string) error {
if !IsZoneValid(zone) {
return ErrInvalidZone
}
datetime, err := setdatetime.NewSetDateTime(
"com.deepin.api.SetDateTime",
"/com/deepin/api/SetDateTime")
if err != nil {
return err
}
defer setdatetime.DestroySetDateTime(datetime)
_, err = datetime.SetTimezone(zone)
if err != nil {
return err
}
return nil
}
var _infos []ZoneInfo
func GetZoneInfoList() []ZoneInfo {
if _infos != nil {
return _infos
}
for _, tmp := range zoneWhiteList {
info := newZoneInfo(tmp.zone)
_infos = append(_infos, *info)
}
return _infos
}
func GetZoneInfo(zone string) (*ZoneInfo, error) {
if !IsZoneValid(zone) {
return nil, ErrInvalidZone
}
info := newZoneInfo(zone)
return info, nil
}
func getZoneDesc(zone string) string {
for _, tmp := range zoneWhiteList {
if zone == tmp.zone {
return tmp.desc
}
}
return zone
}

View File

@ -1,200 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package timezone
import (
C "launchpad.net/gocheck"
"os"
"testing"
)
type testWrapper struct{}
func Test(t *testing.T) {
C.TestingT(t)
}
func init() {
C.Suite(&testWrapper{})
}
func (*testWrapper) TestGetZoneList(c *C.C) {
zoneList := GetZoneInfoList()
c.Check(len(zoneList), C.Equals, len(zoneWhiteList))
}
type testZoneSummary struct {
zone string
dstOffset string
ret bool
}
var infos = []testZoneSummary{
{
zone: "America/Atka",
dstOffset: "09:00",
ret: true,
},
{
zone: "US/Aleutian",
dstOffset: "09:00",
ret: true,
},
{
zone: "Pacific/Niue",
dstOffset: "",
ret: true,
},
{
zone: "Pacific/Niueiii",
dstOffset: "",
ret: false,
},
}
func (*testWrapper) TestZoneValid(c *C.C) {
for _, info := range infos {
c.Check(IsZoneValid(info.zone), C.Equals, info.ret)
}
}
func (*testWrapper) TestNewDSTInfo(c *C.C) {
type testDST struct {
zone string
dst DSTInfo
}
var infos = []testDST{
{
zone: "Asia/Shanghai",
dst: DSTInfo{
Enter: 0,
Leave: 0,
DSTOffset: 0,
},
},
{
zone: "America/New_York",
dst: DSTInfo{
Enter: 1394348400,
Leave: 1414907999,
DSTOffset: -14400,
},
},
}
for _, info := range infos {
e, l, ok := getDSTTime(info.zone, 2014)
c.Check(e, C.Equals, info.dst.Enter)
c.Check(l, C.Equals, info.dst.Leave)
if !ok {
continue
}
off := getOffsetByTimestamp(info.zone, e)
c.Check(off, C.Equals, info.dst.DSTOffset)
}
}
func (*testWrapper) TestZoneDesc(c *C.C) {
var infos = []zoneDesc{
{
zone: "Asia/Beijing",
desc: "Beijing",
},
{
zone: "Pacific/Johnston",
desc: "Pacific/Johnston",
},
}
lang := os.Getenv("LANG")
os.Setenv("LANG", "en_US.UTF-8")
for _, info := range infos {
c.Check(getZoneDesc(info.zone), C.Equals, info.desc)
}
os.Setenv("LANG", lang)
}
func (*testWrapper) TestFindDSTInfo(c *C.C) {
type testDSTData struct {
data dstData
ret bool
}
// dst info for 2014
var infos = []testDSTData{
{
data: dstData{
zone: "US/Alaska",
dst: DSTInfo{
Enter: 1394362800,
Leave: 1414922399,
DSTOffset: -28800,
},
},
ret: true,
},
{
data: dstData{
zone: "Atlantic/Azores",
dst: DSTInfo{
Enter: 1396141200,
Leave: 1414285199,
DSTOffset: 0,
},
},
ret: true,
},
{
data: dstData{
zone: "Pacific/Apia",
dst: DSTInfo{
Enter: 1396706399,
Leave: 1411826400,
DSTOffset: 50400,
},
},
ret: true,
},
{
data: dstData{
zone: "Asia/Shanghai",
dst: DSTInfo{},
},
ret: false,
},
}
for _, info := range infos {
dst, err := findDSTInfo(info.data.zone, "testdata/dst_data")
if info.ret {
c.Check(err, C.IsNil)
c.Check(info.data.dst.Enter, C.Equals, dst.Enter)
c.Check(info.data.dst.Leave, C.Equals, dst.Leave)
c.Check(info.data.dst.DSTOffset, C.Equals, dst.DSTOffset)
} else {
c.Check(dst, C.IsNil)
c.Check(err, C.NotNil)
}
}
}

View File

@ -1,74 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package utils
import (
"pkg.linuxdeepin.com/lib/log"
)
func Printf(logger *log.Logger, format string, v ...interface{}) {
if logger == nil {
return
}
logger.Infof(format, v...)
}
func Println(logger *log.Logger, v ...interface{}) {
if logger == nil {
return
}
logger.Info(v...)
}
func Warningf(logger *log.Logger, format string, v ...interface{}) {
if logger == nil {
return
}
logger.Warningf(format, v...)
}
func Warning(logger *log.Logger, v ...interface{}) {
if logger == nil {
return
}
logger.Warning(v...)
}
func Errorf(logger *log.Logger, format string, v ...interface{}) {
if logger == nil {
return
}
logger.Errorf(format, v...)
}
func Error(logger *log.Logger, v ...interface{}) {
if logger == nil {
return
}
logger.Error(v...)
}

View File

@ -1,85 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package utils
import (
"dbus/com/deepin/api/setdatetime"
"fmt"
)
var (
errUninitialized = fmt.Errorf("SetDateTime Uninitialized")
)
var _setDate *setdatetime.SetDateTime
func InitSetDateTime() error {
if _setDate != nil {
return nil
}
var err error
_setDate, err = setdatetime.NewSetDateTime(
"com.deepin.api.SetDateTime",
"/com/deepin/api/SetDateTime",
)
if err != nil {
return err
}
return nil
}
func DestroySetDateTime() {
if _setDate == nil {
return
}
setdatetime.DestroySetDateTime(_setDate)
_setDate = nil
}
func SetDate(value string) error {
if _setDate == nil {
return errUninitialized
}
_, err := _setDate.SetCurrentDate(value)
if err != nil {
return err
}
return nil
}
func SetTime(value string) error {
if _setDate == nil {
return errUninitialized
}
_, err := _setDate.SetCurrentTime(value)
if err != nil {
return err
}
return nil
}

View File

@ -1,105 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package utils
func IsStrInList(value string, list []string) bool {
for _, s := range list {
if s == value {
return true
}
}
return false
}
func IsYearValid(value int32) bool {
if value >= 1970 {
return true
}
return false
}
func IsMonthValid(value int32) bool {
if value > 0 && value < 13 {
return true
}
return false
}
func IsDayValid(year, month, value int32) bool {
switch month {
case 1, 3, 5, 7, 8, 10, 12:
if value > 0 && value < 32 {
return true
}
case 4, 6, 9, 11:
if value > 0 && value < 31 {
return true
}
case 2:
if IsLeapYear(year) {
if value > 0 && value < 30 {
return true
}
} else {
if value > 0 && value < 29 {
return true
}
}
}
return false
}
func IsHourValid(value int32) bool {
if value >= 0 && value < 24 {
return true
}
return false
}
func IsMinuteValid(value int32) bool {
if value >= 0 && value < 60 {
return true
}
return false
}
func IsSecondValid(value int32) bool {
if value >= 0 && value < 61 {
return true
}
return false
}
func IsLeapYear(value int32) bool {
if value%400 == 0 ||
(value%4 == 0 && value%100 != 0) {
return true
}
return false
}

View File

@ -1,300 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
**/
package utils
import (
C "launchpad.net/gocheck"
"testing"
)
type testWrapper struct{}
func init() {
C.Suite(&testWrapper{})
}
func Test(t *testing.T) {
C.TestingT(t)
}
func (*testWrapper) TestStrInList(c *C.C) {
list := []string{
"1111",
"2222",
"aaaa",
"bbbb",
}
c.Check(IsStrInList("1111", list), C.Equals, true)
c.Check(IsStrInList("aaaa", list), C.Equals, true)
c.Check(IsStrInList("xxxxxx", list), C.Equals, false)
}
type dateInfo struct {
d int32
ret bool
}
func (*testWrapper) TestYearValid(c *C.C) {
var infos = []dateInfo{
{
d: 2014,
ret: true,
},
{
d: 1970,
ret: true,
},
{
d: 1,
ret: false,
},
{
d: -2014,
ret: false,
},
}
for _, info := range infos {
c.Check(IsYearValid(info.d), C.Equals, info.ret)
}
}
func (*testWrapper) TestMonthValid(c *C.C) {
var infos = []dateInfo{
{
d: 1,
ret: true,
},
{
d: 12,
ret: true,
},
{
d: 13,
ret: false,
},
{
d: 0,
ret: false,
},
}
for _, info := range infos {
c.Check(IsMonthValid(info.d), C.Equals, info.ret)
}
}
func (*testWrapper) TestDayValid(c *C.C) {
type mdayInfo struct {
year int32
month int32
mday int32
ret bool
}
var infos = []mdayInfo{
{
year: 2014,
month: 3,
mday: 1,
ret: true,
},
{
year: 2014,
month: 3,
mday: 31,
ret: true,
},
{
year: 2014,
month: 3,
mday: 32,
ret: false,
},
{
year: 2014,
month: 3,
mday: 0,
ret: false,
},
{
year: 2014,
month: 2,
mday: 1,
ret: true,
},
{
year: 2014,
month: 2,
mday: 28,
ret: true,
},
{
year: 2014,
month: 2,
mday: 29,
ret: false,
},
{
year: 2014,
month: 2,
mday: 0,
ret: false,
},
{
year: 2014,
month: 4,
mday: 1,
ret: true,
},
{
year: 2014,
month: 4,
mday: 30,
ret: true,
},
{
year: 2014,
month: 4,
mday: 0,
ret: false,
},
{
year: 2014,
month: 4,
mday: 31,
ret: false,
},
{
year: 2000,
month: 2,
mday: 29,
ret: true,
},
}
for _, info := range infos {
c.Check(IsDayValid(info.year, info.month, info.mday),
C.Equals, info.ret)
}
}
func (*testWrapper) TestHourValid(c *C.C) {
var infos = []dateInfo{
{
d: 0,
ret: true,
},
{
d: 23,
ret: true,
},
{
d: 24,
ret: false,
},
{
d: -1,
ret: false,
},
}
for _, info := range infos {
c.Check(IsHourValid(info.d), C.Equals, info.ret)
}
}
func (*testWrapper) TestMinuteValid(c *C.C) {
var infos = []dateInfo{
{
d: 0,
ret: true,
},
{
d: 59,
ret: true,
},
{
d: 60,
ret: false,
},
{
d: -1,
ret: false,
},
}
for _, info := range infos {
c.Check(IsMinuteValid(info.d), C.Equals, info.ret)
}
}
func (*testWrapper) TestSecondValid(c *C.C) {
var infos = []dateInfo{
{
d: 0,
ret: true,
},
{
d: 60,
ret: true,
},
{
d: 61,
ret: false,
},
{
d: -1,
ret: false,
},
}
for _, info := range infos {
c.Check(IsSecondValid(info.d), C.Equals, info.ret)
}
}
func (*testWrapper) TestLeapYear(c *C.C) {
var infos = []dateInfo{
{
d: 2000,
ret: true,
},
{
d: 2004,
ret: true,
},
{
d: 2100,
ret: false,
},
{
d: 2014,
ret: false,
},
}
for _, info := range infos {
c.Check(IsLeapYear(info.d), C.Equals, info.ret)
}
}

3
debian/control vendored
View File

@ -33,7 +33,6 @@ Depends: ${shlibs:Depends},
acpid,
upower,
bluez5 | bluez (>=5.4),
rfkill,
grub-themes-deepin,
network-manager,
network-manager-pptp,
@ -43,6 +42,8 @@ Depends: ${shlibs:Depends},
network-manager-vpnc,
xcur2png,
xserver-xorg-input-wacom,
iso-codes,
mobile-broadband-provider-info,
policykit-1-gnome,
Conflicts: dde-workspace ( < 2.1+20141028122406 )
Description: daemon handling the DDE session settings

View File

@ -2,6 +2,7 @@ package dock
import (
"dbus/com/deepin/dde/launcher"
"fmt"
"github.com/BurntSushi/xgb/xproto"
"github.com/BurntSushi/xgbutil"
"github.com/BurntSushi/xgbutil/ewmh"
@ -37,9 +38,45 @@ func (m *ClientManager) CurrentActiveWindow() uint32 {
return uint32(activeWindow)
}
func changeWorkspaceIfNeeded(xid xproto.Window) error {
desktopNum, err := xprop.PropValNum(xprop.GetProperty(XU, xid, "_NET_WM_DESKTOP"))
if err != nil {
return fmt.Errorf("Get _NET_WM_DESKTOP failed: %s", err)
}
currentDesktop, err := ewmh.CurrentDesktopGet(XU)
if err != nil {
return fmt.Errorf("Get _NET_CURRENT_DESKTOP failed: %v", err)
}
if currentDesktop == desktopNum {
return fmt.Errorf("No need to change workspace, the current desktop is already %v", currentDesktop)
}
timeStamp, err := ewmh.WmUserTimeGet(XU, xid)
if err != nil {
logger.Warningf("Get timestamp of 0x%x failed: %v", uint32(xid), err)
}
err = ewmh.ClientEvent(XU, XU.RootWin(), "_NET_CURRENT_DESKTOP", int(desktopNum), int(timeStamp))
if err != nil {
return fmt.Errorf("Send ClientMessage Failed: %v", err)
}
return nil
}
func activateWindow(xid xproto.Window) error {
err := changeWorkspaceIfNeeded(xid)
if err != nil {
logger.Warning(err)
}
return ewmh.ActiveWindowReq(XU, xid)
}
// maybe move to apps-builder
func (m *ClientManager) ActiveWindow(xid uint32) bool {
err := ewmh.ActiveWindowReq(XU, xproto.Window(xid))
err := activateWindow(xproto.Window(xid))
if err != nil {
logger.Warning("Actice window failed:", err)
return false
@ -109,12 +146,12 @@ func updateCurrentViewport() {
))
}
func onCurrentWorkspacePre(xid xproto.Window) bool {
// works for old deepin wm.
func checkDeepinWindowViewports(xid xproto.Window) (bool, error) {
viewports, err := xprop.PropValNums(xprop.GetProperty(XU, xid,
"DEEPIN_WINDOW_VIEWPORTS"))
if err != nil {
logger.Warning("get DEEPIN_WINDOW_VIEWPORTS failed", err)
return false
return false, err
}
workspaces := make([][]uint, 0)
@ -127,7 +164,34 @@ func onCurrentWorkspacePre(xid xproto.Window) bool {
if currentViewport == nil {
updateCurrentViewport()
}
return isCoverWorkspace(workspaces, currentViewport)
return isCoverWorkspace(workspaces, currentViewport), nil
}
// works for new deepin wm.
func checkCurrentDesktop(xid xproto.Window) (bool, error) {
num, err := xprop.PropValNum(xprop.GetProperty(XU, xid, "_NET_WM_DESKTOP"))
if err != nil {
return false, err
}
currentDesktop, err := xprop.PropValNum(xprop.GetProperty(XU, XU.RootWin(), "_NET_CURRENT_DESKTOP"))
if err != nil {
return false, err
}
return num == currentDesktop, nil
}
func onCurrentWorkspacePre(xid xproto.Window) bool {
isOnCurrentWorkspace, err := checkDeepinWindowViewports(xid)
if err != nil {
isOnCurrentWorkspace, err = checkCurrentDesktop(xid)
if err != nil {
return false
}
return isOnCurrentWorkspace
}
return isOnCurrentWorkspace
}
func hasMaximizeClientPre(xid xproto.Window) bool {
@ -159,6 +223,7 @@ func isWindowOnPrimaryScreen(xid xproto.Window) bool {
// include shadow
gemo, err := win.DecorGeometry()
if err != nil {
logger.Debug(err)
return false
}

View File

@ -20,9 +20,9 @@ type DesktopAppInfo struct {
gioSupported bool
}
func NewDesktopAppInfo(appId string) *DesktopAppInfo {
func NewDesktopAppInfo(desktopID string) *DesktopAppInfo {
dai := &DesktopAppInfo{nil, nil, false}
dai.DesktopAppInfo = gio.NewDesktopAppInfo(appId)
dai.DesktopAppInfo = gio.NewDesktopAppInfo(desktopID)
if dai.DesktopAppInfo == nil {
return nil
}

View File

@ -52,7 +52,7 @@ func (m *DockedAppManager) init() {
// listen changed.
appList := m.core.GetStrv(DockedApps)
for _, id := range appList {
m.items.PushBack(strings.ToLower(strings.Replace(id, "_", "-", -1)))
m.items.PushBack(normalizeAppID(id))
}
conf := glib.NewKeyFile()
@ -148,15 +148,16 @@ func (m *DockedAppManager) Dock(id, title, icon, cmd string) bool {
}
logger.Debug("id", id, "title", title, "cmd", cmd)
m.items.PushBack(id)
if guess_desktop_id(id) == "" {
// if app := NewDesktopAppInfo(id + ".desktop"); app != nil {
// app.Unref()
// } else {
desktopID := guess_desktop_id(id)
if desktopID == "" {
m.items.PushBack(id)
if e := createScratchFile(id, title, icon, cmd); e != nil {
logger.Warning("create scratch file failed:", e)
return false
}
} else {
id = trimDesktop(desktopID)
m.items.PushBack(id)
}
dbus.Emit(m, "Docked", id)
app := ENTRY_MANAGER.runtimeApps[id]
@ -203,7 +204,7 @@ func (m *DockedAppManager) Undock(id string) bool {
return true
}
tmpId = strings.Replace(id, "-", "_", -1)
tmpId = normalizeAppID(id)
if m.doUndock(tmpId) {
logger.Debug("undock replace - to _:", tmpId)
return true
@ -213,8 +214,9 @@ func (m *DockedAppManager) Undock(id string) bool {
}
func (m *DockedAppManager) findItem(id string) *list.Element {
lowerID := strings.ToLower(id)
for e := m.items.Front(); e != nil; e = e.Next() {
if strings.ToLower(e.Value.(string)) == strings.ToLower(id) {
if strings.ToLower(e.Value.(string)) == lowerID {
return e
}
}

View File

@ -7,7 +7,6 @@ import "pkg.linuxdeepin.com/lib/dbus"
import "github.com/BurntSushi/xgb/xproto"
import "os"
import "path/filepath"
import "strings"
var (
ENTRY_MANAGER = NewEntryManager()
@ -68,8 +67,7 @@ func (m *EntryManager) runtimeAppChanged(xids []xproto.Window) {
// 1. create newfound RuntimeApps
for _, xid := range xids {
if isNormalWindow(xid) {
appId := find_app_id_by_xid(xid,
DisplayModeType(setting.GetDisplayMode()))
appId := find_app_id_by_xid(xid, DisplayModeType(setting.GetDisplayMode()))
if rApp, ok := m.runtimeApps[appId]; ok {
logger.Debugf("%s is already existed, attach xid: 0x%x", appId, xid)
willBeDestroied[appId] = nil
@ -147,8 +145,7 @@ func (m *EntryManager) updateEntry(appId string, nApp *NormalApp, rApp *RuntimeA
}
func (m *EntryManager) createRuntimeApp(xid xproto.Window) *RuntimeApp {
appId := find_app_id_by_xid(xid,
DisplayModeType(setting.GetDisplayMode()))
appId := find_app_id_by_xid(xid, DisplayModeType(setting.GetDisplayMode()))
if appId == "" {
logger.Debug("get appid for", xid, "failed")
return nil
@ -181,7 +178,7 @@ func (m *EntryManager) createNormalApp(id string) {
desktopId := id + ".desktop"
nApp := NewNormalApp(desktopId)
if nApp == nil {
logger.Info("create from scratch file")
logger.Info("get desktop file failed, create", id, "from scratch file")
newId := filepath.Join(
os.Getenv("HOME"),
".config/dock/scratch",
@ -190,6 +187,7 @@ func (m *EntryManager) createNormalApp(id string) {
nApp = NewNormalApp(newId)
if nApp == nil {
logger.Warning("create normal app failed:", id)
DOCKED_APP_MANAGER.Undock(id)
return
}
}
@ -205,7 +203,7 @@ func (m *EntryManager) destroyNormalApp(nApp *NormalApp) {
func initialize() {
ENTRY_MANAGER.listenDockedApp()
for _, id := range loadAll() {
id = strings.ToLower(strings.Replace(id, "_", "-", -1))
id = normalizeAppID(id)
logger.Debug("load", id)
ENTRY_MANAGER.createNormalApp(id)
}

View File

@ -131,9 +131,12 @@ func (m *HideStateManager) UpdateState() {
break
}
if isWindowOnPrimaryScreen(activeWindow) &&
hasMaximizeClientPre(activeWindow) {
logger.Debug("active window is maximized client")
isOnPrimary := isWindowOnPrimaryScreen(activeWindow)
hasMax := hasMaximizeClientPre(activeWindow)
logger.Debug("isOnPrimary:", isOnPrimary, "hasMaxClient:", hasMax)
if isOnPrimary && hasMax {
logger.Info("active window is maximized client")
trigger = TriggerHide
break
}

View File

@ -2,6 +2,7 @@ package dock
import (
"errors"
"fmt"
"path/filepath"
. "pkg.linuxdeepin.com/lib/gettext"
"pkg.linuxdeepin.com/lib/gio-2.0"
@ -10,10 +11,11 @@ import (
)
type NormalApp struct {
Id string
Icon string
Name string
Menu string
Id string
DesktopID string
Icon string
Name string
Menu string
changedCB func()
@ -22,19 +24,20 @@ type NormalApp struct {
dockItem *MenuItem
}
func NewNormalApp(id string) *NormalApp {
basename := strings.ToLower(filepath.Base(id[:len(id)-8]))
app := &NormalApp{Id: strings.Replace(basename, "_", "-", -1)}
logger.Debug("NewNormalApp:", id)
func NewNormalApp(desktopID string) *NormalApp {
app := &NormalApp{Id: normalizeAppID(trimDesktop(desktopID)), DesktopID: desktopID}
logger.Info("NewNormalApp:", desktopID)
var core *DesktopAppInfo
if strings.ContainsRune(id, filepath.Separator) {
core = NewDesktopAppInfoFromFilename(id)
if strings.ContainsRune(desktopID, filepath.Separator) {
core = NewDesktopAppInfoFromFilename(desktopID)
} else {
core = NewDesktopAppInfo(id)
core = NewDesktopAppInfo(desktopID)
if core == nil {
logger.Debug("guess desktop")
if newId := guess_desktop_id(app.Id + ".desktop"); newId != "" {
newId := guess_desktop_id(app.Id)
logger.Info(fmt.Sprintf("guess desktop: %q", newId))
if newId != "" {
core = NewDesktopAppInfo(newId)
app.DesktopID = newId
}
}
}
@ -52,13 +55,13 @@ func NewNormalApp(id string) *NormalApp {
}
func (app *NormalApp) createDesktopAppInfo() *DesktopAppInfo {
core := NewDesktopAppInfo(app.Id)
core := NewDesktopAppInfo(app.DesktopID)
if core != nil {
return core
}
if newId := guess_desktop_id(app.Id + ".desktop"); newId != "" {
if newId := guess_desktop_id(app.Id); newId != "" {
core = NewDesktopAppInfo(newId)
if core != nil {
return core

View File

@ -7,13 +7,21 @@ import (
"github.com/BurntSushi/xgbutil/ewmh"
"github.com/BurntSushi/xgbutil/icccm"
"pkg.linuxdeepin.com/lib/dbus"
"sync"
)
type Region struct {
}
var initShapeOnce sync.Once
func initShape() {
initShapeOnce.Do(func() {
shape.Init(XU.Conn())
})
}
func NewRegion() *Region {
shape.Init(XU.Conn())
r := Region{}
return &r
@ -43,6 +51,7 @@ func (r *Region) getDockWindow() (xproto.Window, error) {
}
func (r *Region) GetDockRegion() xproto.Rectangle {
initShape()
defer func() {
if err := recover(); err != nil {
logger.Warning("Region::GetDockRegion", err)

View File

@ -34,8 +34,9 @@ type WindowInfo struct {
}
type RuntimeApp struct {
Id string
lock sync.RWMutex
Id string
DesktopID string
lock sync.RWMutex
//TODO: multiple xid window
xids map[xproto.Window]*WindowInfo
@ -58,13 +59,13 @@ type RuntimeApp struct {
}
func (app *RuntimeApp) createDesktopAppInfo() *DesktopAppInfo {
core := NewDesktopAppInfo(app.Id)
core := NewDesktopAppInfo(app.DesktopID)
if core != nil {
return core
}
if newId := guess_desktop_id(app.Id + ".desktop"); newId != "" {
if newId := guess_desktop_id(app.Id); newId != "" {
core = NewDesktopAppInfo(newId)
if core != nil {
return core
@ -79,13 +80,17 @@ func NewRuntimeApp(xid xproto.Window, appId string) *RuntimeApp {
return nil
}
app := &RuntimeApp{
Id: strings.ToLower(appId),
xids: make(map[xproto.Window]*WindowInfo),
Id: strings.ToLower(appId),
DesktopID: appId + ".desktop",
xids: make(map[xproto.Window]*WindowInfo),
}
core := NewDesktopAppInfo(appId + ".desktop")
core := NewDesktopAppInfo(app.DesktopID)
if core == nil {
if newId := guess_desktop_id(appId + ".desktop"); newId != "" {
if newId := guess_desktop_id(app.Id); newId != "" {
core = NewDesktopAppInfo(newId)
if core != nil {
app.DesktopID = newId
}
}
}
if core != nil {
@ -370,7 +375,7 @@ func find_app_id_by_xid(xid xproto.Window, displayMode DisplayModeType) string {
var appId string
if displayMode == DisplayModeModernMode {
if id, err := xprop.PropValStr(xprop.GetProperty(XU, xid, "_DDE_DOCK_APP_ID")); err == nil {
appId = strings.Replace(strings.ToLower(id), "_", "-", -1)
appId = getAppIDFromDesktopID(normalizeAppID(id))
logger.Debug("get app id from _DDE_DOCK_APP_ID", appId)
return appId
}
@ -388,23 +393,21 @@ func find_app_id_by_xid(xid xproto.Window, displayMode DisplayModeType) string {
if name != "" {
pid = lookthroughProc(name)
} else {
appId = strings.Replace(strings.ToLower(wmClassName), "_", "-",
-1)
appId = getAppIDFromDesktopID(normalizeAppID(wmClassName))
logger.Debug("get Pid failed, using wm class name as app id", appId)
return appId
}
}
iconName, _ := ewmh.WmIconNameGet(XU, xid)
if pid == 0 {
appId = strings.Replace(strings.ToLower(wmClassName), "_", "-",
-1)
appId = normalizeAppID(wmClassName)
logger.Debug("get window name failed, using wm class name as app id", appId)
return appId
} else {
}
appId = find_app_id(pid, name, wmInstance, wmClassName, iconName)
appId = strings.Replace(strings.ToLower(appId), "_", "-", -1)
logger.Debug("get appid", appId)
appId = getAppIDFromDesktopID(normalizeAppID(appId))
logger.Debug(fmt.Sprintf("get appid %q", appId))
return appId
}
@ -608,7 +611,7 @@ func (app *RuntimeApp) Activate(x, y int32) error {
//TODO: handle multiple xids
switch {
case !contains(app.state, "_NET_WM_STATE_FOCUSED"):
ewmh.ActiveWindowReq(XU, app.CurrentInfo.Xid)
activateWindow(app.CurrentInfo.Xid)
case contains(app.state, "_NET_WM_STATE_FOCUSED"):
s, err := icccm.WmStateGet(XU, app.CurrentInfo.Xid)
if err != nil {

View File

@ -120,16 +120,6 @@ func (s *Setting) init() bool {
return false
}
s.displayMode = DisplayModeType(s.core.GetEnum(DisplayModeKey))
s.hideMode = HideModeType(s.core.GetEnum(HideModeKey))
if s.hideMode == HideModeAutoHide {
s.hideMode = HideModeSmartHide
s.core.SetEnum(HideModeKey, int(HideModeSmartHide))
}
s.clockType = ClockType(s.core.GetEnum(ClockTypeKey))
s.displayDate = s.core.GetBoolean(DisplayDateKey)
s.displayWeek = s.core.GetBoolean(DisplayWeekKey)
s.listenSettingChange(HideModeKey, func(g *gio.Settings, key string) {
s.hideModeLock.Lock()
defer s.hideModeLock.Unlock()
@ -220,6 +210,20 @@ func (s *Setting) init() bool {
s.displayWeek = s.core.GetBoolean(DisplayWeekKey)
dbus.Emit(s, "DisplayWeekChanged", s.displayWeek)
})
// at least one read operation must be called after signal connected, otherwise,
// the signal connection won't work from glib 2.43.
// NB: https://github.com/GNOME/glib/commit/8ff5668a458344da22d30491e3ce726d861b3619
s.displayMode = DisplayModeType(s.core.GetEnum(DisplayModeKey))
s.hideMode = HideModeType(s.core.GetEnum(HideModeKey))
if s.hideMode == HideModeAutoHide {
s.hideMode = HideModeSmartHide
s.core.SetEnum(HideModeKey, int32(HideModeSmartHide))
}
s.clockType = ClockType(s.core.GetEnum(ClockTypeKey))
s.displayDate = s.core.GetBoolean(DisplayDateKey)
s.displayWeek = s.core.GetBoolean(DisplayWeekKey)
return true
}
@ -236,7 +240,7 @@ func (s *Setting) GetHideMode() int32 {
func (s *Setting) SetHideMode(_mode int32) bool {
mode := HideModeType(_mode)
logger.Debug("[Setting.SetHideMode]:", mode)
ok := s.core.SetEnum(HideModeKey, int(mode))
ok := s.core.SetEnum(HideModeKey, int32(mode))
return ok
}
@ -247,7 +251,7 @@ func (s *Setting) GetDisplayMode() int32 {
func (s *Setting) SetDisplayMode(_mode int32) bool {
mode := DisplayModeType(_mode)
logger.Debug("[Setting.SetDisplayMode]:", mode)
ok := s.core.SetEnum(DisplayModeKey, int(mode))
ok := s.core.SetEnum(DisplayModeKey, int32(mode))
return ok
}
@ -258,7 +262,7 @@ func (s *Setting) GetClockType() int32 {
func (s *Setting) SetClockType(_clockType int32) bool {
clockType := ClockType(_clockType)
logger.Debug("clock type changed to:", clockType)
ok := s.core.SetEnum(ClockTypeKey, int(clockType))
ok := s.core.SetEnum(ClockTypeKey, int32(clockType))
return ok
}

View File

@ -2,9 +2,11 @@ package dock
import (
"encoding/base64"
"fmt"
"io/ioutil"
"path/filepath"
"pkg.linuxdeepin.com/lib/gio-2.0"
"regexp"
"strings"
)
@ -23,13 +25,63 @@ func getEntryId(name string) (string, bool) {
return "", false
}
func trimDesktop(desktopID string) string {
desktopIDLen := len(desktopID)
if desktopIDLen == 0 {
return ""
}
if desktopIDLen > 8 {
return strings.TrimSuffix(desktopID, ".desktop")
}
panic(fmt.Sprintf("%q is not a desktop id", desktopID))
}
func normalizeAppID(candidateID string) string {
normalizedAppID := strings.Replace(strings.ToLower(candidateID), "_", "-", -1)
return normalizedAppID
}
var _DesktopAppIdReg = regexp.MustCompile(`(?:[^.]+\.)*(?P<desktopID>[^.]+)\.desktop`)
func getAppIDFromDesktopID(candidateID string) string {
desktopID := guess_desktop_id(candidateID)
logger.Debug(fmt.Sprintf("get desktop id: %q", desktopID))
if desktopID == "" {
return candidateID
}
appID := normalizeAppID(trimDesktop(desktopID))
return appID
}
// the key is appID
// the value is desktopID
var _appIDCache map[string]string = make(map[string]string)
func guess_desktop_id(appId string) string {
logger.Debug(fmt.Sprintf("guess_desktop_id for %q", appId))
if desktopID, ok := _appIDCache[appId]; ok {
logger.Debug(appId, "is in cache")
return desktopID
}
desktopID := appId + ".desktop"
allApp := gio.AppInfoGetAll()
for _, app := range allApp {
baseName := filepath.Base(gio.ToDesktopAppInfo(app).GetFilename())
lowerBaseName := strings.ToLower(baseName)
if appId == lowerBaseName ||
appId == strings.Replace(lowerBaseName, "_", "-", -1) {
normalizedDesktopID := normalizeAppID(baseName)
if normalizedDesktopID == desktopID {
_appIDCache[appId] = baseName
return baseName
}
// TODO: this is not a silver bullet, fix it later.
appIDs := _DesktopAppIdReg.FindStringSubmatch(normalizedDesktopID)
if len(appIDs) == 2 && appIDs[1] == appId {
_appIDCache[appId] = baseName
return baseName
}
}

View File

@ -22,7 +22,6 @@
package grub2
import (
"os"
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/log"
)
@ -39,12 +38,12 @@ func Start() {
err := dbus.InstallOnSession(grub)
if err != nil {
logger.Errorf("register dbus interface failed: %v", err)
os.Exit(1)
return
}
err = dbus.InstallOnSession(grub.theme)
if err != nil {
logger.Errorf("register dbus interface failed: %v", err)
os.Exit(1)
return
}
// initialize grub2 after dbus service installed to ensure

View File

@ -169,7 +169,7 @@ func (obj *Manager) createCustomShortcut(id int32, name, action, shortcut string
return false
}
gs.SetInt(CUSTOM_KEY_ID, int(id))
gs.SetInt(CUSTOM_KEY_ID, id)
gs.SetString(CUSTOM_KEY_NAME, name)
gs.SetString(CUSTOM_KEY_ACTION, action)
gs.SetString(CUSTOM_KEY_SHORTCUT, shortcut)

View File

@ -44,16 +44,6 @@ const (
MANAGER_IFC = "com.deepin.daemon.KeyBinding"
MEDIAKEY_PATH = "/com/deepin/daemon/MediaKey"
MEDIAKEY_IFC = "com.deepin.daemon.MediaKey"
COMPIZ_SETTINGS_CORE = "org.compiz.core"
COMPIZ_SETTINGS_MOVE = "org.compiz.move"
COMPIZ_SETTINGS_RESIZE = "org.compiz.resize"
COMPIZ_SETTINGS_VPSWITCH = "org.compiz.vpswitch"
COMPIZ_SETTINGS_PUT = "org.compiz.put"
COMPIZ_SETTINGS_WALL = "org.compiz.wall"
COMPIZ_SETTINGS_SHIFT = "org.compiz.shift"
COMPIZ_SETTINGS_SWITCHER = "org.compiz.switcher"
COMPIZ_SETTINGS_BASE_PATH = "/org/compiz/profiles/deepin/plugins/"
)
var (

View File

@ -22,29 +22,9 @@
package keybinding
import (
"pkg.linuxdeepin.com/lib/gio-2.0"
"strings"
)
var (
coreSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_CORE,
COMPIZ_SETTINGS_BASE_PATH+"core/")
moveSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_MOVE,
COMPIZ_SETTINGS_BASE_PATH+"move/")
resizeSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_RESIZE,
COMPIZ_SETTINGS_BASE_PATH+"resize/")
vpswitchSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_VPSWITCH,
COMPIZ_SETTINGS_BASE_PATH+"vpswitch/")
putSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_PUT,
COMPIZ_SETTINGS_BASE_PATH+"put/")
wallSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_WALL,
COMPIZ_SETTINGS_BASE_PATH+"wall/")
shiftSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_SHIFT,
COMPIZ_SETTINGS_BASE_PATH+"shift/")
switcherSettings = gio.NewSettingsWithPath(COMPIZ_SETTINGS_SWITCHER,
COMPIZ_SETTINGS_BASE_PATH+"switcher/")
)
func formatCompizShortcut(shortcut string) string {
logger.Info("formatCompizShortcut:", shortcut)
strs := strings.Split(shortcut, ACCEL_DELIM)
@ -62,153 +42,3 @@ func formatCompizShortcut(shortcut string) string {
return tmp
}
func (m *Manager) setCompizSettings(id int32, key, value string) {
k, ok := compizKeysMap[key]
if !ok {
logger.Warningf("'%s' not in compizKeysMap", key)
return
}
shortcut := formatCompizShortcut(value)
if id >= 600 && id < 650 {
coreSettings.SetString(k, shortcut)
} else if id >= 650 && id < 700 {
moveSettings.SetString(k, shortcut)
} else if id >= 700 && id < 750 {
resizeSettings.SetString(k, shortcut)
} else if id >= 750 && id < 800 {
vpswitchSettings.SetString(k, shortcut)
} else if id >= 800 && id < 850 {
putSettings.SetString(k, shortcut)
} else if id >= 850 && id < 900 {
wallSettings.SetString(k, shortcut)
} else if id >= 900 && id < 950 {
shiftSettings.SetString(k, shortcut)
} else if id >= 950 && id < 1000 {
switcherSettings.SetString(k, shortcut)
}
}
func (m *Manager) listenCompizSettings() {
coreSettings.Connect("changed", func(s *gio.Settings, key string) {
switch key {
case "show-desktop-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("show-desktop", shortcut)
case "close-window-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("close", shortcut)
case "maximize-window-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("maximize", shortcut)
case "unmaximize-window-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("unmaximize", shortcut)
case "minimize-window-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("minimize", shortcut)
case "toggle-window-shaded-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("toggle-shaded", shortcut)
case "window-menu-key":
shortcut := coreSettings.GetString(key)
updateSystemSettings("activate-window-menu", shortcut)
}
})
moveSettings.Connect("changed::initiate-key", func(s *gio.Settings, key string) {
shortcut := moveSettings.GetString(key)
updateSystemSettings("begin-move", shortcut)
})
resizeSettings.Connect("changed::initiate-key", func(s *gio.Settings, key string) {
shortcut := resizeSettings.GetString(key)
updateSystemSettings("begin-resize", shortcut)
})
vpswitchSettings.Connect("changed", func(s *gio.Settings, key string) {
switch key {
case "switch-to-1-key":
shortcut := vpswitchSettings.GetString(key)
updateSystemSettings("switch-to-workspace-1", shortcut)
case "switch-to-2-key":
shortcut := vpswitchSettings.GetString(key)
updateSystemSettings("switch-to-workspace-2", shortcut)
case "switch-to-3-key":
shortcut := vpswitchSettings.GetString(key)
updateSystemSettings("switch-to-workspace-3", shortcut)
case "switch-to-4-key":
shortcut := vpswitchSettings.GetString(key)
updateSystemSettings("switch-to-workspace-4", shortcut)
}
})
putSettings.Connect("changed", func(s *gio.Settings, key string) {
switch key {
case "put-viewport-1-key":
shortcut := putSettings.GetString(key)
updateSystemSettings("put-viewport-1-key", shortcut)
case "put-viewport-2-key":
shortcut := putSettings.GetString(key)
updateSystemSettings("put-viewport-2-key", shortcut)
case "put-viewport-3-key":
shortcut := putSettings.GetString(key)
updateSystemSettings("put-viewport-3-key", shortcut)
case "put-viewport-4-key":
shortcut := putSettings.GetString(key)
updateSystemSettings("put-viewport-4-key", shortcut)
}
})
wallSettings.Connect("changed", func(s *gio.Settings, key string) {
switch key {
case "left-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("switch-to-workspace-left", shortcut)
case "right-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("switch-to-workspace-right", shortcut)
case "up-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("switch-to-workspace-up", shortcut)
case "down-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("switch-to-workspace-down", shortcut)
case "left-window-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("move-to-workspace-left", shortcut)
case "right-window-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("move-to-workspace-right", shortcut)
case "up-window-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("move-to-workspace-up", shortcut)
case "down-window-key":
shortcut := wallSettings.GetString(key)
updateSystemSettings("move-to-workspace-down", shortcut)
}
})
shiftSettings.Connect("changed", func(s *gio.Settings, key string) {
switch key {
case "next-key":
shortcut := shiftSettings.GetString(key)
updateSystemSettings("next-key", shortcut)
case "prev-key":
shortcut := shiftSettings.GetString(key)
updateSystemSettings("prev-key", shortcut)
}
})
switcherSettings.Connect("changed", func(s *gio.Settings, key string) {
switch key {
case "next-key":
shortcut := switcherSettings.GetString(key)
updateSystemSettings("switch-applications", shortcut)
case "prev-key":
shortcut := switcherSettings.GetString(key)
updateSystemSettings("switch-applications-backward", shortcut)
}
})
}

View File

@ -266,23 +266,20 @@ func (obj *Manager) listenSettings() {
obj.setPropCustomList(getCustomListInfo())
}
})
bindGSettings.GetStrv(BIND_KEY_VALID_LIST)
sysGSettings.Connect("changed", func(s *gio.Settings, key string) {
if id, ok := getAccelIdByName(key); ok {
invalidFlag := false
//invalidFlag := false
if isInvalidConflict(id) {
invalidFlag = true
//invalidFlag = true
}
shortcut := getSystemKeyValue(key, false)
//shortcut := getSystemKeyValue(key, false)
if id >= 0 && id < 300 {
grabKeyPairs(PrevSystemPairs, false)
grabKeyPairs(getSystemKeyPairs(), true)
} else if id >= 600 && id < 1000 {
if !invalidFlag {
obj.setCompizSettings(id, key, shortcut)
}
}
if isIdInSystemList(id) {
@ -294,6 +291,7 @@ func (obj *Manager) listenSettings() {
}
}
})
sysGSettings.GetStrv("file-manager")
}
func (obj *Manager) listenAllCustomSettings() {
@ -322,4 +320,5 @@ func (obj *Manager) listenCustomSettings(id int32) {
obj.setPropCustomList(getCustomListInfo())
})
gs.GetString("name")
}

View File

@ -159,7 +159,6 @@ func newManager() *Manager {
m.listenKeyEvents()
m.listenSettings()
m.listenCompizSettings()
m.listenAllCustomSettings()
m.updateProps()

View File

@ -27,9 +27,9 @@ import (
. "pkg.linuxdeepin.com/lib/gettext"
)
func (lang *LangSelector) onGenLocaleStatus() {
lang.setDate.ConnectGenLocaleStatus(func(ok bool, state string) {
err := lang.handleLocaleChanged(ok, state)
func (lang *LangSelector) onLocaleSuccess() {
lang.lhelper.ConnectSuccess(func(ok bool, reason string) {
err := lang.handleLocaleChanged(ok, reason)
if err != nil {
lang.logger.Warning(err)
lang.setPropCurrentLocale(getLocale())
@ -48,7 +48,7 @@ func (lang *LangSelector) onGenLocaleStatus() {
})
}
func (lang *LangSelector) handleLocaleChanged(ok bool, state string) error {
func (lang *LangSelector) handleLocaleChanged(ok bool, reason string) error {
if !ok || lang.LocaleState != LocaleStateChanging {
return ErrLocaleChangeFailed
}

View File

@ -22,7 +22,7 @@
package langselector
import (
"dbus/com/deepin/api/setdatetime"
"dbus/com/deepin/api/localehelper"
libnetwork "dbus/com/deepin/daemon/network"
"dbus/org/freedesktop/notifications"
"fmt"
@ -31,7 +31,6 @@ import (
"path"
"pkg.linuxdeepin.com/dde-daemon/langselector/language_info"
"pkg.linuxdeepin.com/lib/log"
dutils "pkg.linuxdeepin.com/lib/utils"
"strings"
)
@ -59,11 +58,17 @@ type LangSelector struct {
LocaleState int32
logger *log.Logger
setDate *setdatetime.SetDateTime
lhelper *localehelper.LocaleHelper
}
type envInfo struct {
key string
value string
}
type envInfos []envInfo
func newLangSelector(l *log.Logger) *LangSelector {
lang := LangSelector{}
lang := LangSelector{LocaleState: LocaleStateChanged}
if l != nil {
lang.logger = l
@ -72,11 +77,11 @@ func newLangSelector(l *log.Logger) *LangSelector {
}
var err error
lang.setDate, err = setdatetime.NewSetDateTime(
"com.deepin.api.SetDateTime",
"/com/deepin/api/SetDateTime")
lang.lhelper, err = localehelper.NewLocaleHelper(
"com.deepin.api.LocaleHelper",
"/com/deepin/api/LocaleHelper")
if err != nil {
lang.logger.Warning("New SetDateTime Failed:", err)
lang.logger.Warning("New LocaleHelper Failed:", err)
return nil
}
@ -86,12 +91,12 @@ func newLangSelector(l *log.Logger) *LangSelector {
}
func (lang *LangSelector) Destroy() {
if lang.setDate == nil {
if lang.lhelper == nil {
return
}
setdatetime.DestroySetDateTime(lang.setDate)
lang.setDate = nil
localehelper.DestroyLocaleHelper(lang.lhelper)
lang.lhelper = nil
}
func sendNotify(icon, summary, body string) error {
@ -129,9 +134,9 @@ func isNetworkEnable() (bool, error) {
func getLocale() string {
filename := path.Join(os.Getenv("HOME"), userLocaleFilePAM)
locale, err := getLocaleFromFile(filename)
if err != nil {
if err != nil || len(locale) == 0 {
locale, err = getLocaleFromFile(systemLocaleFile)
if err != nil {
if err != nil || len(locale) == 0 {
locale = defaultLocale
}
@ -149,7 +154,6 @@ func getLocale() string {
func writeUserLocale(locale string) error {
filename := path.Join(os.Getenv("HOME"), userLocaleFilePAM)
return writeUserLocalePam(locale, filename)
}
@ -157,95 +161,83 @@ func writeUserLocale(locale string) error {
* gnome locale config
**/
func writeUserLocalePam(locale, filename string) error {
fp, err := os.Create(filename + "~")
if err != nil {
return err
}
defer fp.Close()
contents := constructPamFile(locale, filename)
if _, err = fp.WriteString(contents); err != nil {
return err
}
fp.Sync()
os.Rename(filename+"~", filename)
return nil
var content = generatePamEnvFile(locale, filename)
return ioutil.WriteFile(filename, []byte(content), 0644)
}
func constructPamFile(locale, filename string) string {
if !dutils.IsFileExist(filename) {
return generatePamContents(locale)
}
contents, err := ioutil.ReadFile(filename)
if err != nil {
return generatePamContents(locale)
}
lines := strings.Split(string(contents), "\n")
var tmp string
for i, line := range lines {
if i != 0 {
tmp += "\n"
func generatePamEnvFile(locale, filename string) string {
var (
lFound bool //LANG
lgFound bool //LANGUAGE
content string
infos, _ = readEnvFile(filename)
length = len(infos)
lang = strings.Split(locale, ".")[0]
)
for i, info := range infos {
if info.key == "LANG" {
lFound = true
info.value = locale
} else if info.key == "LANGUAGE" {
lgFound = true
info.value = lang
}
strs := strings.Split(line, "=")
if strs[0] == "LANG" {
tmp += strs[0] + "=" + locale
continue
} else if strs[0] == "LANGUAGE" {
lcode := strings.Split(locale, ".")[0]
tmp += strs[0] + "=" + lcode
continue
content += fmt.Sprintf("%s=%s", info.key, info.value)
if i != length-1 {
content += "\n"
}
tmp += line
}
if !lFound {
content += fmt.Sprintf("LANG=%s", locale)
if !lgFound {
content += "\n"
}
}
if !lgFound {
content += fmt.Sprintf("LANGUAGE=%s", lang)
}
return tmp
}
func generatePamContents(locale string) string {
contents := ""
str := "LANG=" + locale + "\n"
contents += str
tmp := strings.Split(locale, ".")
str = "LANGUAGE=" + tmp[0] + "\n"
contents += str
return contents
return content
}
func getLocaleFromFile(filename string) (string, error) {
if !dutils.IsFileExist(filename) {
return "", ErrFileNotExist
}
contents, err := ioutil.ReadFile(filename)
infos, err := readEnvFile(filename)
if err != nil {
return "", err
}
var locale string
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
strs := strings.Split(line, "=")
if len(strs) != 2 {
for _, info := range infos {
if info.key != "LANG" {
continue
}
if strs[0] != "LANG" {
continue
}
locale = strings.Trim(strs[1], "\"")
break
}
if len(locale) == 0 {
return "", ErrLocaleNotFound
locale = info.value
}
return locale, nil
}
func readEnvFile(file string) (envInfos, error) {
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
var (
infos envInfos
lines = strings.Split(string(content), "\n")
)
for _, line := range lines {
var array = strings.Split(line, "=")
if len(array) != 2 {
continue
}
infos = append(infos, envInfo{
key: array[0],
value: array[1],
})
}
return infos, nil
}

View File

@ -33,33 +33,43 @@ type localeInfo struct {
}
func (lang *LangSelector) SetLocale(locale string) error {
if lang.LocaleState == LocaleStateChanging {
return nil
}
if len(locale) == 0 || !language_info.IsLocaleValid(locale,
language_info.LanguageListFile) {
return fmt.Errorf("Invalid locale: %v", locale)
}
if lang.setDate == nil {
return fmt.Errorf("SetDateTime object is nil")
if lang.lhelper == nil {
return fmt.Errorf("LocaleHelper object is nil")
}
if lang.CurrentLocale == locale {
return nil
}
lang.LocaleState = LocaleStateChanging
lang.setPropCurrentLocale(locale)
go func() {
lang.LocaleState = LocaleStateChanging
lang.setPropCurrentLocale(locale)
if ok, _ := isNetworkEnable(); !ok {
err := sendNotify("", "", Tr("System language is being changed, please wait..."))
err := sendNotify("", "",
Tr("System language is being changed, please wait..."))
if err != nil {
lang.logger.Warning("sendNotify failed:", err)
}
} else {
err := sendNotify("", "", Tr("System language is being changed with an installation of lacked language packages, please wait..."))
err := sendNotify("", "",
Tr("System language is being changed with an installation of lacked language packages, please wait..."))
if err != nil {
lang.logger.Warning("sendNotify failed:", err)
}
}
lang.setDate.GenLocale(locale)
err := lang.lhelper.GenerateLocale(locale)
if err != nil {
lang.logger.Warning("GenerateLocale failed:", err)
lang.LocaleState = LocaleStateChanged
}
}()
return nil

Some files were not shown because too many files have changed in this diff Show More