#!/bin/bash
# Script for manipulating modules in Porteus
# Author: Brokenman <brokenman@porteus.org>

# Switch to root
if [ `whoami` != "root" ]; then
    echo "Please enter your root password below"
    su - -c "/opt/porteus-scripts/xmodtools"
    exit
fi

# Variables
TITLE="Porteus Module Tools"
CONFPATH="/etc/modtools"
CONFIG="$CONFPATH/modtoolsrc"
WRK1="/tmp/convertmod/in"
WRK2="/tmp/convertmod/out"
WRK3="/tmp/convertmod/tmp"
WRKBASE="/tmp/convertmod"
HELPTXT="$CONFPATH/modtools-help.txt"
mod=/tmp/mod
mpoint=/mnt/loop
x=`ls -1 /dev/loop* | awk -F/ '{print$3}' | tr -d [:alpha:] | sort -n | tail -n1`
lp=$(($x+1))
TMP=/tmp/wrk
title="Porteus Module Tools"

# Cleanup any existing working dir
[ -d $WRK1 ] && rm -rf $WRK1
[ -d $WRK2 ] && rm -rf $WRK2
[ -d $WRK3 ] && rm -rf $WRK3
[ -d $TMP ] && rm -Rf $TMP

helpme() {
if [ ! -f $HELPTXT ]; then
	touch $HELPTXT

cat << EOF > $HELPTXT
#######################################
PORTEUS MODULE TOOLS - by Brokeman
#######################################
.
Upon first run, this script will ask you to point the way to your porteus optional 
modules folder. You will only be asked this once and a config file will be placed at:
$CONFPATH/modtoolsrc
.
=====================================================
=========== INCLUDED CONSOLE COMMANDS  ==============
Porteus Module Tools also includes these console commands:
.
modtools  -  Start the modtools GUI
mloop /path/to/module  - Mount chosen module on loop
rempkg  -  Start the remove package dialog
extpkg  -  Start the extract package dialog
act modulename -  activate modules from console
act can be typed from any location and you only have to type part of the name.
=====================================================
.
.
_______________
ACTIVATE MODULE

Type in the beginning of a module's name and it will be activated. You can prepend all
of your office apps with "office" (e.g office-gcalc.xzm) and activate then all by
typing in "office"
.
_______________
ACTIVATE FOLDER

Type in the name of a folder in your optional modules directory and all of the modules
inside will be activated. This is useful if you store all modules with dependencies in
one single folder. You can activate and deactivate them whenever you please.
.
_______________
CONVERT MODULE

Convert modules from other distros from squashfs-3 to squashfs-4 .xzm.
.
_______________
CONVERT FOLDER

The same as converting a module (above) only an entire folder of modules can be
converted at once.
.
_______________
UNPACK MODULE

Unpack a module into a directory so you can browse and edit the files. You can
use the 'create module' menu to make a module after you've finished editing.
.
_______________
MOUNT MODULE ON LOOP

The module of your choice will be mounted on a loop device as read-only. You can
browse or copy the file. To unmount the loop type: uloop into a console.
.
_______________
CREATE MODULE FROM FOLDER

Create a module from a folder that you specify. For example you may want to
create a bash profile. Create the folders test/rootcopy/root/ and put your bash
inside this. (e.g /rootcopy/root/.bash_profile) and make a module from test.
.
_______________
CREATE MODULE FROM CHANGES

Easily make a module from the changes you have made to the default Porteus install.
This is a great way to backup the changes you have made. If you make more than
one changes module you can merge them together with the 'MERGE MODULES' option.
WARNING: This can take alot of time, don't make changes while it is running.
.
_______________
MERGE MODULES

When you want to merge your modules together use this option. Perhaps you have
made multiple modules from your changes directory? You can merge them together with
this option and place the single resulting module in place of the many.
.
_______________
TGZ2XZM

Converts a slackware .tgz/.txz package into a Porteus compatible .xzm module. The
package is unpack, then stripped of unnecessary files before being repacked
as a Porteus module.
.
_______________
REMPKG

Remove a chosen package from a base Porteus module. This relies on the chosen
module having a packages file in var/log/packages
.
_______________
EXTPKG

Extract a package from either a Porteus base module or a running Porteus
install. This works by reading the file list in /var/log/packages. The
resulting module will be placed on your desktop.
_______________
MERGE TGZ2XZM

Choose a folder full of .tgz/.txz slackware packages and they will be merged into
a single Porteus compatible modules. The tgz/txz files are unpacked, then stripped
of unnecessary files before being repacked as a Porteus .xzm module.
.
_______________
REMOVE CONFIG

When you first run this script it places a config file in the following path:
$CONFPATH/modtoolsrc. This tells the script that you have already used it
before and there is no need to download anyhting. It also uses this config
to find the place that you keep all of your modules. Remove the config if
you want to store your modules in a different place, or you made a mistake
with the path in the first instance.
.
EOF
fi
Xdialog --title "Porteus modtools" --textbox $HELPTXT 700 400
}

chkbut() {

case $? in
	1 )
	[ -d /tmp/wrk* ] && rm -rf /tmp/wrk
	[ -d $mod ] && rm -rf $mod
	exit
	;;
	255 )
	[ -d /tmp/wrk* ] && rm -rf /tmp/wrk
	[ -d $mod ] && rm -rf $mod
	exit
	;;
esac
}

# Catch output from dialog
catch(){
unset answ
answ=`cat .log`
rm .log
}

# Create Porteus modtools config file
modpath() {
Xdialog --title "$TITLE" --wrap --left --msgbox "The following window will ask you to choose your Porteus optional module folder. This is the folder that you keep all of your modules in. \n\nYou will only need to enter this path once and a configuration file will be saved." 15 60

Xdialog --title "Choose your module folder" --dselect /mnt 0 0 2> .log
catch && CONFIGFILE=${answ}
chkbut
if [ "$CONFIGFILE" == "" ]; then
	Xdialog --title "$TITLE" --no-cancel --msgbox "You must select a module folder to continue. You will only have to enter this path once." 0 0
	exit
fi

Xdialog --title "Confirmation" --yesno "You chose: $CONFIGFILE \n\n is this correct?" 0 0
[ $? -eq 1 ] && modpath

mkdir -p $CONFPATH
touch $CONFIG
echo "[modfolder]" > $CONFIG
echo $CONFIGFILE >> $CONFIG
}

# Another version of progress bar
module_progress_bar(){
p=0
while true; do
  p=`grep == .log | awk '{print$NF}' | sed 's/%//'`
  echo $p
  if [ "$p" == "100" ]; then
    p="100"
    echo $p
    sleep 2
    break
      else
    echo $p
  fi
done | Xdialog --title "$TITLE" --gauge "$1" 8 70 $p
}

# An xdialog progress box
progress(){
(
while [ "$per" != "100" ]; do
per=`grep == .log|awk '{print$NF}'|sed 's/%//'`
echo $per
done) | Xdialog --title "$1" --progress "" 5 50 99 0
rm .log
}

# An xdialog info box
info_box(){
(
counter=0
while [ "$counter" != "100" ]; do
counter=`grep == .log|tail -n1 |awk '{print$NF}'|sed 's/%//'`
echo XXX
echo "Processing: $counter%"
echo XXX
counter=`grep == .log|awk '{print$NF}'|sed 's/%//'`
done
) |
Xdialog --title "Porteus Module Tools" --infobox "Please wait" 5 50 0
PID=$!
if [ $? -eq 1 ]; then
  kill $PID
fi
#rm .log
}

# Check if nothing was entered into choose folder dialog
check_zero_input(){
if [ "$answ" == "" ]; then
  Xdialog --title "$TITLE" --msgbox "You must enter a path. Exiting now" 0 0 &
  exit
fi
}

# Convert .lzm module to .xzm module
cmodule() {
Xdialog --title "Convert an .lzm module to .xzm" --fselect $MODFOLDER 0 0 2> .log
[ $? -eq 1 ] && exit 
catch && CON=${answ}

# Check that file is .lzm extension
EXT=${CON##*.}
if [ "$EXT" != "lzm" ]; then
   Xdialog --title "Extension mismatch" \
   --msgbox "This is not an .lzm module! Exiting." 0 0
   exit
fi

[ -d $WRK1 ] && rm -rf $WRK1
mkdir -p $WRK1

# Check if module is squash3 or squash4
TYP=`file $CON | grep "endian"`
NAME=$(echo $CON | awk -F/ '{print $NF}' | sed 's/\(.*\)\..*/\1/')

# Get size of module
SIZE=`du $CON | awk '{print$1}'`

# Choose unsquash based on sniff above
if [ -z "$TYP" ]; then
  unsquashfs3 -f -dest $WRK1 $CON > /dev/null 2>&1
    else
  unsquashfs -f -dest $WRK1 $CON > .log &
  module_progress_bar $CON && rm .log
fi

COUNT=10
dir2xzm $WRK1 $MODFOLDER/$NAME.xzm > .log 2>&1 &
module_progress_bar $NAME.xzm && rm .log

Xdialog --msgbox "Your module is ready: $MODFOLDER/$NAME.xzm" 0 0
konqueror $MODFOLDER &
exit
}

# Convert a folder of modules from .lzm to .xzm
cfolder() {
Xdialog --title "$TITLE" --backtitle "Please choose a folder containing .lzm files" \
--dselect $MODFOLDER 0 0 2> .log
catch && CON=${answ}
rm .log

Xdialog --title "$TITLE" --yesno "You chose $CON. \n\n Is this correct?" 0 0
[ $? -eq 1 ] && cfolder

# Check that .lzm file exist
CHK=`ls $CON/*.lzm`
if [ -z "$CHK" ]; then
  Xdialog --title "Mismatched modules" --msgbox "Sorry, no .lzm modules found" 0 0
  exit
fi

for mod in $CON/*.lzm; do
	TYP=`file $mod | grep "endian"`
	NAME=$(echo $mod | awk -F/ '{print $NF}' | sed 's/\(.*\)\..*/\1/' | sed 's/\.sq4.*//')
	mkdir -p $WRK1
	if [ -z "$TYP" ]; then
	unsquashfs3 -f -dest $WRK1 $mod > /dev/null 2>&1
		else
	unsquashfs -f -dest $WRK1 $mod > .log &
	module_progress_bar $mod && rm .log
	fi
	
	dir2xzm $WRK1 $CON/$NAME.xzm > .log 2>&1 &
	module_progress_bar $NAME && rm .log
	rm -rf $WRK1
done

Xdialog --title "Porteus modtools" \
--msgbox "Your modules were successfully converted. They are in $CON" 0 0
konqueror $CON &
exit
}

# Activate a single module
activ() {
if [ $ACTCNT -eq 0 ]; then
	Xdialog --title "Porteus module tools" \
	--msgbox "No modules found by that name" 0 0
	exit
		else
for mod in $(find $MODFOLDER/$ACT* -name "*.xzm");
	do activate $mod;
	done
fi
exit
}

# Unpack a chosen module
unpackmod() {
[ -d $MODFOLDER/unpacked ] && rm -Rf $MODFOLDER/unpacked >/dev/null
Xdialog --title "Unpack a module" --fselect $MODFOLDER 0 0 2> .log
catch && UMODULE=${answ}
[ $? -eq 1 ] && exit 
[ -d $MODFOLDER/unpacked ] && rm -rf $MODFOLDER/unpacked
mkdir $MODFOLDER/unpacked

# Check extension
EXT=${UMODULE##*.}
if [ "$EXT" != "lzm" -a "$EXT" != "xzm" ]; then
   Xdialog --title "Extension mismatch" \
   --msgbox "This is not an .lzm or .xzm module! Exiting." 0 0
   exit
fi

#Check if module is squash3 or squash4
TYP=`file $UMODULE | grep "endian"`

# Choose unsquash based on sniff above
if [ -z "$TYP" ]; then
  unsquashfs3 -f -dest $MODFOLDER/unpacked $UMODULE > /dev/null 2>&1
    else
  unsquashfs -f -dest $MODFOLDER/unpacked $UMODULE > .log 2>&1 &
  module_progress_bar $UMODULE && rm .log
fi
unset answ
Xdialog --msgbox "Your  module has been unpacked to \n $MODFOLDER/unpacked" 0 0
konqueror $MODFOLDER &
exit
}

# Mount a module on a loop
loopmount() {
culoop
# Ask user for module to mount
Xdialog --fselect $MODFOLDER 0 0 2> .log
chkbut
catch && LCHOICE=${answ}
MCHOICE=`echo $LCHOICE | awk -F / '{print$NF}'`
# Check for loop mount dir
if [ ! -d $mpoint ]; then
	mkdir $mpoint
		else
	xls=`ls $mpoint`
fi

if [ "$xls" != "" ]; then
	umount $mpoint
fi

# Create a new loop
mknod /dev/loop$lp b 7 $lp

# Mount file on loop
mount -t squashfs -o loop $LCHOICE $mpoint > /dev/null 2>&1

# Make tmp dir if not exist
[ -d $TMP ] || mkdir $TMP

Xdialog --title "Porteus Module Tools" \
--msgbox "$MCHOICE is mounted READ ONLY at /mnt/loop \n to unmount type:uloop in console" 10 70
konqueror /mnt/loop &
exit
}

# Generate uloop file for unmounting mountpoint
culoop() {
if [ ! -f /opt/porteus-scripts/uloop ]; then
cat > /opt/porteus-scripts/uloop << "EOF"
#!/bin/bash
if [ -d /mnt/loop ]; then
	mls=`ls /mnt/loop`
fi

if [ "$mls" != "" ]; then
	umount /mnt/loop
fi
echo
echo "/mnt/loop has been unmounted"
echo

exit
EOF
chmod +x /opt/porteus-scripts/uloop
fi
}

# Create a module from a folder
fold2mod() {
Xdialog --title "Convert folder to module" --dselect $MODFOLDER 0 0 2> .log
catch && FMOD=${answ}

Xdialog --title "$TITLE" --yesno "You chose $FMOD \n\n Is this correct?" 0 0
[ $? -eq 1 ] && fold2mod

Xdialog --inputbox "Please enter name for the new module." 0 0 "" 2> .log
catch && FM=${answ} && rm .log
FMODNAME=`echo $FM  | sed 's/\.xzm.*//'`
COUNT=10
dir2xzm $FMOD $MODFOLDER/$FMODNAME.xzm > .log 2>&1 &
module_progress_bar $FMODNAME.xzm && rm .log

#Xdialog --msgbox "Your module has been created. Find it at $MODFOLDER/$FMODNAME.xzm \n you may delete folder now if you wish." 0 0
#konqueror $MODFOLDER
exit	
}

# Merge a folder of modules together
mergemods() {
Xdialog --title "Select a folder of modules" --dselect $MODFOLDER 0 0 2> .log
catch && MMOD=${answ}
chkbut
unset answ

Xdialog --title "$TITLE" --yesno "You chose $MMOD. \n\n Is this correct?" 0 0
[ $? -eq 1 ] && mergemods

[ ! -d $MMOD/tmp ] && mkdir $MMOD/tmp
for mm in $MMOD/*.*; do
	if [ "${mm##*.}" != "xzm" ]; then
	Xdialog --msgbox "$mm is NOT an .xzm file. Exiting now" 0 0
	exit
		else
	xzm2dir $mm $MMOD/tmp > .log &
	module_progress_bar $mm && rm .log
	fi
done

Xdialog --inputbox "Enter a name for new module" 0 0 2> .log
catch && NM=${answ}
NEWM=`echo $NM  | sed 's/\.xzm.*//'`
dir2xzm $MMOD/tmp $MMOD/$NEWM.xzm > .log 2>&1 &
module_progress_bar $NEWM && rm .log
rm -rf $MMOD/tmp
sleep 1
Xdialog --msgbox "Your module has been created!! \nIt is inside $MMOD" 0 0
konqueror $MMOD &
exit
}

# Convert a tgz/txz package to porteus module
tgz_xzm() {
Xdialog --title "Choose tgz/txz file" --fselect $MODFOLDER 0 0 2> .log
catch && tgzsrc=${answ}
chkbut
tgzname=$(echo $tgzsrc | awk -F/ '{print$NF}')
name=$(echo $tgzname | sed 's/\(.*\)\..*/\1/')
mkdir $MODFOLDER/tmpwrk$$
Xdialog --no-buttons --title "Portes modtools" --infobox "Copying packages now" 0 0 2000 &
installpkg -root $MODFOLDER/tmpwrk$$ $tgzsrc > /dev/null 2>&1
pushd $MODFOLDER/tmpwrk$$ > /dev/null 2>&1
if [ -d usr/man ]; then
	find usr/man -type l -name "*.gz" | xargs -r gunzip -f > /dev/null 2>&1
		else
	find . | xargs file | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded >  /dev/null 2>&1
fi

[ -d usr/doc ] && rm -rf usr/doc
[ -d usr/share/doc ] && rm -rf usr/share/doc
popd > /dev/null 2>&1
Xdialog --title "$TITLE" --no-buttons --infobox "Converting $name" 0 0 2000 &
dir2xzm $MODFOLDER/tmpwrk$$ $MODFOLDER/$name.xzm
rm -rf $MODFOLDER/tmpwrk*
sleep 1
Xdialog --msgbox "Your tgz/txz file has been converted and can be found at: \n$MODFOLDER/$name.xzm." 0 0
if [ -x /usr/bin/konqueror ]; then
  konqueror $MODFOLDER &
    else
  if [ -x /usr/sbin/pcmanfm ]; then
    /usr/sbin/pcmanfm $MODFOLDER &
  fi
fi
exit 
}

# Convert a folder of tgz/txz packages into a single Porteus module
mtgz_xzm() {
Xdialog --title "Convert folder of tgz/txz to module" --dselect $MODFOLDER 0 0 2> .log
catch && FTGZ=${answ}
[ $? -eq 1 ] && exit

Xdialog --title "$TITLE" --yesno "You chose $FTGZ. \n\n Is this correct?" 0 0
[ $? -eq 1 ] && mtgz_xzm

mkdir -p $FTGZ/tmpwrk$$
cp $FTGZ/*.tgz $FTGZ/*.txz $FTGZ/tmpwrk$$
Xdialog --title "Portes modtools" --no-buttons --infobox \
"Processing packages now" 0 0 2000 &
cd $FTGZ/tmpwrk$$
for b in *.tgz *.txz; do
  installpkg -root . $b > /dev/null 2>&1
  Xdialog --title "$TITLE" --no-buttons --infobox "$b" 0 0 1000 &
  rm $b
done

[ -d usr/doc ] && rm -rf usr/doc
[ -d usr/share/doc ] && rm -rf usr/share/doc
if [ -d usr/man ]; then
find usr/man -type l -name "*.gz" | xargs -r gunzip -f > /dev/null 2>&1
fi
find . | xargs file | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded > /dev/null 2>&1
Xdialog --inputbox "Please enter a name for your module" 0 0 2> .log
catch && ME=${answ}
MNAME=`echo $ME | sed 's/\.xzm.*//'`
unset answ
cd ../
Xdialog --nobuttons --infobox "Creating module $MNAME.xzm" 0 0 2000 &
dir2xzm tmpwrk$$ $FTGZ/$MNAME.xzm > .log 2>&1
rm -rf tmpwrk$$
Xdialog --msgbox "Your .tgz files have been merged into a module: \n$FTGZ/$MNAME.xzm" 0 0
konqueror $FTGZ &
exit
}

# Make a module from changes
changemod(){
append=`date +%y%m%d`

Xdialog --title "$TITLE" --wrap --left --yesno \
"You should save the resulting module somewhere OUTSIDE the live filesystem like a removeable drive. You can't save your changes if they continually being written to, it will result in a runaway process.\n\nWould you like to continue?" 12 70
chkbut

Xdialog --title "Porteus changes saver" \
--backtitle "Where would you like to save the module?" \
--dselect $MODFOLDER 0 0 2> .log
chkbut
catch && SAV=${answ}
check_zero_input

dir2xzm /mnt/live/memory/changes $SAV/changes-$append.xzm > .log 2>&1 &
info_box
rm .log
#module_progress_bar changes-$append.xzm
Xdialog --msgbox "Your changes are saved as $SAV/changes-$append.xzm module" 0 0
exit
}

# Extract a package from a module
extpkg() {
sh /opt/porteus-scripts/extpkg
exit
}

# Remove package from module
rempkg() {
sh /opt/porteus-scripts/rempkg
exit
}

########## CONFIG FOLDER CHECK ##########
#########################################

if [ -f $CONFIG ]; then
	MODFOLDER=$(grep -A1 "[modfolder]" $CONFIG | tail -1)
		else
		modpath
	MODFOLDER=$(grep -A1 '[modfolder]' $CONFIG | tail -1)
fi

LIVE=$(echo $MODFOLDER | awk -F / '{print$3}')

##### BEGIN GUI MENU ##########

Xdialog --title "Author: Brokenman" --menubox "Porteus Module Tool - Select an option:" 0 45 20 1 "Easy activate module" 2 "Easy activate folder" 3 "Unpack a module" 4 "Mount module on loop" 5 "Convert single .lzm to .xzm" 6 "Convert folder of .lzm to .xzm" 7 "Make module from folder" 8 "Make module from changes" 9 "Merge modules together" 10 "Convert .tgz/.txz to .xzm" 11 "Merge multiple .tgz/.txz to .xzm" 12 "Extract a chosen package" 13 "Remove a chosen package" 14 "Help file" 15 "Remove config file" 2> .log
catch && CHOICE=${answ}
chkbut
##### END GUI MENU ############

if [ $CHOICE -eq 15 ]; then
	rm -rf $CONFIG
	Xdialog --title "$TITLE" \
	--msgbox "The config file has been removed. Next time you \n start you will be asked for modules path again." 0 0
	exit
fi

if [ $CHOICE -eq 1 ]; then
	Xdialog --title "Activate a module" --inputbox "Enter a module name into the space provided" 0 0 2> .log
	catch && ACT=${answ}
	ACTCNT=`find $MODFOLDER/$ACT* -name "*.xzm" | wc -l`
	activ
	unset answ
		elif 
	[ $CHOICE -eq 2 ]; then
	Xdialog --title "Activate a folder of modules" --dselect $MODFOLDER 0 0 2> .log
	catch && ACT=${answ}
		for ma in $ACT/*.xzm; do
			activate $ma
		done
unset answ
Xdialog --msgbox "All modules found have been activated!" 0 0
exit
fi


[ $CHOICE -eq 3 ] && unpackmod
[ $CHOICE -eq 5 ] && cmodule
[ $CHOICE -eq 6 ] && cfolder
[ $CHOICE -eq 7 ] && fold2mod
[ $CHOICE -eq 9 ] && mergemods
[ $CHOICE -eq 10 ] && tgz_xzm
[ $CHOICE -eq 11 ] && mtgz_xzm
[ $CHOICE -eq 12 ] && extpkg
[ $CHOICE -eq 13 ] && rempkg
[ $CHOICE -eq 14 ] && helpme
[ $CHOICE -eq 4 ] && loopmount
[ $CHOICE -eq 8 ] && changemod

exit