mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-04 17:33:05 +00:00
Merge remote-tracking branch 'cr.ssh/develop'
This commit is contained in:
commit
be157d8768
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,8 +5,6 @@ test-*
|
||||
test_*
|
||||
_*
|
||||
*.*~
|
||||
*.cfg
|
||||
*.ini
|
||||
.#*
|
||||
.test
|
||||
*/*.test
|
||||
|
10
Makefile
10
Makefile
@ -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/
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
92
accounts/checkers/checkers_test.go
Normal file
92
accounts/checkers/checkers_test.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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
2
accounts/checkers/testdata/passwd
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
test1:x:1001:1001::/home/test1:/bin/bash
|
||||
test2:x:1002:1002::/home/test2:/bin/bash
|
182
accounts/checkers/username.go
Normal file
182
accounts/checkers/username.go
Normal 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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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"
|
||||
)
|
@ -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
|
||||
}
|
||||
|
@ -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
191
accounts/manager.go
Normal 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
168
accounts/manager_ifc.go
Normal 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
|
||||
}
|
@ -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
85
accounts/polkit.go
Normal 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
|
||||
}
|
85
accounts/testdata/adduser.conf
vendored
85
accounts/testdata/adduser.conf
vendored
@ -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_]*\$"
|
85
accounts/testdata/adduser1.conf
vendored
85
accounts/testdata/adduser1.conf
vendored
@ -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_]*\$"
|
398
accounts/user.go
398
accounts/user.go
@ -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]
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
36
accounts/username_checker/testdata/passwd
vendored
36
accounts/username_checker/testdata/passwd
vendored
@ -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
|
@ -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{}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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
62
accounts/users/guest.go
Normal 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
216
accounts/users/list.go
Normal 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
325
accounts/users/manager.go
Normal 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
|
||||
}
|
@ -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
142
accounts/users/passwd.go
Normal 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
|
||||
}
|
@ -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
131
accounts/users/prop.go
Normal 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
10
accounts/users/testdata/adduser.conf
vendored
Normal 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
10
accounts/users/testdata/adduser1.conf
vendored
Normal 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
|
2
accounts/users/testdata/autologin/custom.conf
vendored
Normal file
2
accounts/users/testdata/autologin/custom.conf
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
[daemon]
|
||||
DefaultSession=deepin
|
3
accounts/users/testdata/autologin/custom_autologin.conf
vendored
Normal file
3
accounts/users/testdata/autologin/custom_autologin.conf
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[daemon]
|
||||
DefaultSession=deepin
|
||||
AutomaticLogin=wen
|
1
accounts/users/testdata/autologin/default-display-manager
vendored
Normal file
1
accounts/users/testdata/autologin/default-display-manager
vendored
Normal file
@ -0,0 +1 @@
|
||||
/usr/sbin/lightdm
|
5
accounts/users/testdata/autologin/kdmrc
vendored
Normal file
5
accounts/users/testdata/autologin/kdmrc
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
[X-:0-Core]
|
||||
AutoLoginEnable=false
|
||||
AutoLoginLocked=false
|
||||
AutoLoginUser=
|
||||
ClientLogFile=.xsession-errors
|
5
accounts/users/testdata/autologin/kdmrc_autologin
vendored
Normal file
5
accounts/users/testdata/autologin/kdmrc_autologin
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
[X-:0-Core]
|
||||
AutoLoginEnable=true
|
||||
AutoLoginLocked=false
|
||||
AutoLoginUser=wen
|
||||
ClientLogFile=.xsession-errors
|
3
accounts/users/testdata/autologin/lightdm.conf
vendored
Normal file
3
accounts/users/testdata/autologin/lightdm.conf
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[SeatDefaults]
|
||||
greeter-session=lightdm-deepin-greeter
|
||||
user-session=deepin
|
4
accounts/users/testdata/autologin/lightdm_autologin.conf
vendored
Normal file
4
accounts/users/testdata/autologin/lightdm_autologin.conf
vendored
Normal 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
9
accounts/users/testdata/group
vendored
Normal 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
3
accounts/users/testdata/passwd
vendored
Normal 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
4
accounts/users/testdata/shadow
vendored
Normal 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:::
|
216
accounts/users/users_test.go
Normal file
216
accounts/users/users_test.go
Normal 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
173
accounts/utils.go
Normal 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)
|
||||
}
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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")
|
||||
}
|
@ -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()
|
||||
|
||||
|
259
bin/user-config/config_datas.go
Normal file
259
bin/user-config/config_datas.go
Normal 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
69
bin/user-config/main.go
Normal 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)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
143
datetime/ifc.go
143
datetime/ifc.go
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
1
datetime/testdata/timezone
vendored
1
datetime/testdata/timezone
vendored
@ -1 +0,0 @@
|
||||
Asia/Shanghai
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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...)
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
3
debian/control
vendored
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
58
dock/util.go
58
dock/util.go
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 (
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -159,7 +159,6 @@ func newManager() *Manager {
|
||||
|
||||
m.listenKeyEvents()
|
||||
m.listenSettings()
|
||||
m.listenCompizSettings()
|
||||
m.listenAllCustomSettings()
|
||||
m.updateProps()
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user